home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Zoom 2
/
Zoom - Release 2 (1996)(Active Software)[!].iso
/
music
/
utilities
/
octamed4devkit
/
proplayer
/
proplayer_special.a
< prev
next >
Wrap
Text File
|
1994-03-02
|
107KB
|
3,116 lines
; SPECIAL VERSION FOR Mark Knight at Mindscape
; Search for the string 'SPECIAL...' to find things changed from
; the standard proplayer.a version.
; © RBF Software 1994
; As with the rest of this disks contents,NOT for release as public domain.
; However, the routine may be used within programs that are released as
; public domain, ( no charge ).
; As with the rest of the routines on this disk, If intended for use within
; a commercial or chargeable program, you must register, ( see licencing ).
;============================================================================
; proplayer.a
; ~~~~~~~~~~~
; $VER: proplayer 5.004 (09.06.1993)
;
; The music player routine for MMD0/MMD1/MMD2 MED/OctaMED
; four-channel modules.
;
; Written by Teijo Kinnunen.
; If you find bugs in this routine, please notify:
; Teijo Kinnunen
; Oksantie 19
; FIN-86300 OULAINEN
; FINLAND
;
;============================================================================
;****** Feature control ******
;
MIDI EQU 0 ;1 = include MIDI code
AUDDEV EQU 1 ;1 = allocate channels using audio.device
SYNTH EQU 1 ;1 = include synth-sound handler
CHECK EQU 1 ;1 = do range checkings (track, sample in mem etc.)
RELVOL EQU 1 ;1 = include relative volume handling code
IFFMOCT EQU 1 ;1 = play IFF multi-octave samples/ExtSamples correctly
HOLD EQU 1 ;1 = handle hold/decay
PLAYMMD0 EQU 1 ;1 = play old MMD0 modules
;
; The less features you include, the faster and shorter the play-routine
; will be.
;****** Timing control ******
;
VBLANK EQU 0 ;1 = use VBlank interrupt (when absolutely necessary)
CIAB EQU 1 ;1 = use CIA timers (default)
;
; Please use CIAB whenever possible to avoid problems with variable
; VBlank speeds and to allow the use of command F01 - FF0 (set tempo)
; If both are set to 0, the timing is left for you (never set both to 1!!),
; then you just call _IntHandler for each timing pulse.
;============================================================================
;If you are making a demo/game with only a single tune you'd like to
;incorporate in the code (like "easyplayer.a" of MED V3), set the following
;flag to 1. This requires an assembler with INCBIN (or equivalent) directive.
;You have to type the module name into the INCBIN statement (located near the
;end of this file, on line 2052).
EASY EQU 0
;Call _startmusic to play the music, and _endmusic to stop it (before
;exiting). Note: don't call _startmusic twice!! This would cause the module
;to be relocated twice (= Guru). If you need to stop and continue playing,
;don't use the EASY routines, use PlayModule/StopPlayer... instead.
;============================================================================
; The MMD structure offsets
mmd_id EQU 0
mmd_modlen EQU 4
mmd_songinfo EQU 8
; these two for MMD2s only!
mmd_psecnum EQU 12
mmd_pseq EQU 14
;
mmd_blockarr EQU 16
mmd_smplarr EQU 24
mmd_expdata EQU 32
mmd_pstate EQU 40 ; <0 = play song, 0 = don't play, >0 = play block
mmd_pblock EQU 42
mmd_pline EQU 44
mmd_pseqnum EQU 46
mmd_counter EQU 50
mmd_songsleft EQU 51
; The Song structure
; Instrument data here (504 bytes = 63 * 8)
msng_numblocks EQU 504
msng_songlen EQU 506
msng_playseq EQU 508
msng_deftempo EQU 764
msng_playtransp EQU 766
msng_flags EQU 767
msng_flags2 EQU 768
msng_tempo2 EQU 769
; msng_trkvol applies to MMD0/MMD1 only.
msng_trkvol EQU 770
msng_mastervol EQU 786
msng_numsamples EQU 787
; Fields below apply to MMD2 modules only.
msng_pseqs EQU 508
msng_sections EQU 512
msng_trkvoltbl EQU 516
msng_numtracks EQU 520
msng_numpseqs EQU 522
; Instrument data
inst_repeat EQU 0
inst_replen EQU 2
inst_midich EQU 4
inst_midipreset EQU 5
inst_svol EQU 6
inst_strans EQU 7
; Audio hardware offsets
ac_ptr EQU $00
ac_len EQU $04
ac_per EQU $06
ac_vol EQU $08
; Trackdata sizes
T03SZ EQU 98
T415SZ EQU 20
; Maximum number of tracks allowed. If you don't need this much tracks,
; you can decrease the number to save some space. (Be sure that the
; song really has no more than MAX_NUMTRACKS tracks. Minimum allowed
; value = 4.)
MAX_NUMTRACKS EQU 64
; This value is used for MMD0/1 conversion. If MAX_NUMTRACKS <= 16,
; this should be the same. If MAX_NUMTRACKS > 16, this should be 16.
MAX_MMD1_TRACKS EQU 16
SECTION "text",CODE
IFNE EASY
XDEF _startmusic,_endmusic
_startmusic lea easymod,a2
bsr.s _RelocModule
bsr.w _InitPlayer
lea easymod,a0
bra.w _PlayModule
_endmusic bra.w _RemPlayer
; ***** The relocation routine *****
reloci move.l 24(a2),d0
beq.s xloci
movea.l d0,a0
moveq #0,d0
move.b msng_numsamples(a1),d0 ;number of samples
subq.b #1,d0
relocs: bsr.s relocentr
move.l -4(a0),d3 ;sample ptr
beq.s nosyn
move.l d3,a3
tst.w 4(a3)
bpl.s nosyn ;type >= 0
move.w 20(a3),d2 ;number of waveforms
lea 278(a3),a3 ;ptr to wf ptrs
subq.w #1,d2
relsyn add.l d3,(a3)+
dbf d2,relsyn
nosyn dbf d0,relocs
xloci rts
norel addq.l #4,a0
rts
relocentr tst.l (a0)
beq.s norel
add.l d1,(a0)+
rts
_RelocModule movem.l a2-a3/d2-d3,-(sp)
move.l a2,d1 ;d1 = ptr to start of module
bsr.s relocp
movea.l 8(a2),a1
bsr.s reloci
rel_lp bsr.s relocb
cmp.b #'2',3(a2) ;MMD2?
bne.s norelmmd2
bsr.w relocmmd2sng
norelmmd2 move.l 32(a2),d0 ;extension struct
beq.s rel_ex
move.l d0,a0
bsr.s relocentr ;ptr to next module
bsr.s relocentr ;InstrExt...
addq.l #4,a0 ;skip sizes of InstrExt
bsr.s relocentr ;annotxt
addq.l #4,a0 ;annolen
bsr.s relocentr ;InstrInfo
addq.l #8,a0
bsr.s relocentr ;rgbtable (not useful for most people)
addq.l #4,a0 ;skip channelsplit
bsr.s relocentr ;NotationInfo
bsr.s relocentr ;songname
addq.l #4,a0 ;skip song name length
bsr.s relocentr ;MIDI dumps
bsr.s relocmdd
move.l d0,a0
move.l (a0),d0
beq.s rel_ex
move.l d0,a2
bsr.s relocp
movea.l 8(a2),a1
bra.s rel_lp
rel_ex movem.l (sp)+,d2-d3/a2-a3
rts
relocp lea 8(a2),a0
bsr.s relocentr
addq.l #4,a0
bsr.s relocentr
addq.l #4,a0
bsr.s relocentr
addq.l #4,a0
bra.s relocentr
relocb move.l 16(a2),d0
beq.s xlocb
movea.l d0,a0
move.w msng_numblocks(a1),d0
subq.b #1,d0
rebl bsr.s relocentr
dbf d0,rebl
cmp.b #'T',3(a2)
beq.s xlocb
cmp.b #'1',3(a2) ;test MMD type
bge.s relocbi
xlocb rts
relocmdd tst.l -(a0)
beq.s xlocmdd
movea.l (a0),a0
move.w (a0),d0 ;# of msg dumps
addq.l #8,a0
mddloop beq.s xlocmdd
bsr relocentr
bsr.s relocdmp
subq.w #1,d0
bra.s mddloop
xlocmdd rts
relocdmp move.l -4(a0),d3
beq.s xlocdmp
exg.l a0,d3 ;save
addq.l #4,a0
bsr relocentr ;reloc data pointer
move.l d3,a0 ;restore
xlocdmp rts
relocbi move.w msng_numblocks(a1),d0
move.l a0,a3
biloop subq.w #1,d0
bmi.s xlocdmp
move.l -(a3),a0
addq.l #4,a0
bsr relocentr ;BlockInfo ptr
tst.l -(a0)
beq.s biloop
move.l (a0),a0
bsr relocentr ;hldata
bsr relocentr ;block name
bra.s biloop
; take care of the new features of MMD2s
relocmmd2sng move.l mmd_songinfo(a2),a0
lea msng_pseqs(a0),a0
bsr relocentr ;playseqtable
bsr relocentr ;sectiontable
bsr relocentr ;trackvols
move.w 2(a0),d0 ;numpseqs
move.l -12(a0),a0 ;get back to playseqtable
subq.w #1,d0
psqtblloop bsr relocentr
dbf d0,psqtblloop
rts
ENDC
; -------- _ChannelOff: Turn off a channel -------------------------------
_ChannelOff: ;d0 = channel #
lea DB,a0
lea trackdataptrs-DB(a0),a1
lsl.w #2,d0
adda.w d0,a1
lsr.w #2,d0
movea.l (a1),a1
IFNE MIDI
move.b trk_prevmidin(a1),d1 ;first: is it MIDI??
beq.s notcomidi ;not a midi note
; -------- TURN OFF MIDI TRACK -------------------------------------------
lea noteondata-DB(a0),a0
choff_midi: clr.b trk_prevmidin(a1)
move.b d1,1(a0)
bmi.s notamigatrk
move.b trk_prevmidich(a1),(a0) ;prev midi channel
clr.b 2(a0)
or.b #$90,(a0) ;note off
moveq #3,d0
bra.w _AddMIDIData
ENDC
notcomidi: cmp.b #4,d0
bge.s notamigatrk
; -------- TURN OFF AMIGA-CHANNEL ----------------------------------------
IFNE SYNTH
clr.l trk_synthptr(a1)
clr.b trk_synthtype(a1)
ENDC
clr.w trk_soffset(a1)
moveq #1,d1
lsl.w d0,d1
move.w d1,$dff096
notamigatrk: rts
; -------- SoundOff: Turn off all channels -------------------------------
SoundOff: move.l d2,-(sp)
moveq #MAX_NUMTRACKS-1,d2
SO_loop0 move.l d2,d0
bsr.s _ChannelOff
dbf d2,SO_loop0
clr.l _module ;play nothing
move.l (sp)+,d2
SO_rts rts
; -------- _PlayNote: The note playing routine ---------------------------
_PlayNote: ;d7(w) = trk #, d1 = note #, d3(w) = instr # a3 = addr of instr
; -------- CHECK INSTRUMENT (existence, type) ----------------------------
move.l a3,d4
beq.s SO_rts
moveq #0,d4
bset d7,d4 ;d4 is mask for this channel
movea.l mmd_smplarr(a2),a0
add.w d3,d3 ;d3 = instr.num << 2
add.w d3,d3
move.l 0(a0,d3.w),d5 ;get address of instrument
IFNE MIDI
bne.s inmem
tst.b inst_midich(a3) ;is MIDI channel set?
ENDC
IFNE CHECK
beq.w pnote_rts ; NO!!!
ENDC
; -------- ADD TRANSPOSE -------------------------------------------------
inmem add.b msng_playtransp(a4),d1 ;add play transpose
add.b inst_strans(a3),d1 ;and instr. transpose
; -------- TURN OFF CHANNEL DMA, IF REQUIRED -----------------------------
cmp.b #4,d7
bge.s nodmaoff ;track # >= 4: not an Amiga channel
move.l d5,a1
IFNE SYNTH
tst.l d5
beq.s stpdma
tst.b trk_synthtype(a5)
ble.s stpdma ;prev. type = sample/hybrid
cmp.w #-1,4(a1) ;type == SYNTHETIC??
beq.s nostpdma
ENDC
stpdma: move.w d4,$dff096 ;stop this channel (dmacon)
nostpdma:
IFNE SYNTH
clr.l trk_synthptr(a5)
ENDC
nodmaoff: subq.b #1,d1
IFNE MIDI
; -------- KILL PREVIOUS MIDI NOTE ---------------------------------------
move.b trk_prevmidin(a5),d3 ;get prev. midi note
beq.s noprevmidi
clr.b trk_prevmidin(a5)
lea noteondata+2-DB(a6),a0
clr.b (a0)
move.b d3,-(a0)
bmi.s noprevmidi
move.b trk_prevmidich(a5),-(a0) ;prev midi channel
or.b #$90,(a0) ;note off
move.w d1,-(sp)
moveq #3,d0
bsr.w _AddMIDId
move.w (sp)+,d1
noprevmidi:
; -------- IF MIDI NOTE, CALL MIDI NOTE ROUTINE --------------------------
tst.b inst_midich(a3)
bne.w handleMIDInote
ENDC
; -------- SET SOME AMIGA-CHANNEL PARAMETERS -----------------------------
IFNE CHECK
cmp.w #4,d7 ;track > 3???
bge.w pnote_rts ;no Amiga instruments here!!!
ENDC
; handle decay (for tracks 0 - 3 only!!)
IFNE HOLD
clr.b trk_fadespd(a5) ;no fade yet..
move.b trk_initdecay(a5),trk_decay(a5) ;set decay
ENDC
clr.w trk_vibroffs(a5) ;clr vibrato/tremolo offset
or.w d4,dmaonmsk-DB(a6)
move.l d5,a0
IFNE SYNTH
; -------- IF SYNTH NOTE, CALL SYNTH ROUTINE -----------------------------
tst.w 4(a0)
bmi.w handleSynthnote
clr.b trk_synthtype(a5)
ENDC
; -------- CHECK NOTE RANGE ----------------------------------------------
tlwtst0 tst.b d1
bpl.s notenot2low
add.b #12,d1 ;note was too low, octave up
bra.s tlwtst0
notenot2low cmp.b #62,d1
ble.s endpttest
sub.b #12,d1 ;note was too high, octave down
endpttest
moveq #0,d2
moveq #0,d3
lea _periodtable+32-DB(a6),a1
move.b trk_finetune(a5),d2 ;finetune value
add.b d2,d2
add.b d2,d2 ;multiply by 4...
ext.w d2 ;extend
movea.l 0(a1,d2.w),a1 ;period table address
IFNE IFFMOCT
move.w 4(a0),d0 ;Soitin-struct in a0
bne.s gid_notnormal ;note # in d1 (0 - ...)
ENDC
gid_cont_ext move.l a1,trk_periodtbl(a5)
add.b d1,d1
move.w 0(a1,d1.w),d5 ;put period to d5
move.l a0,d0
addq.l #6,d0 ;Skip structure
move.l (a0),d1 ;length
add.l d0,d1 ;sample end pointer
move.w inst_repeat(a3),d2
move.w inst_replen(a3),d3
IFNE IFFMOCT
bra gid_setrept
gid_addtable dc.b 0,6,12,18,24,30
gid_divtable dc.b 31,7,3,15,63,127
gid_notnormal cmp.w #7,d0
blt.s gid_not_ext
suba.w #48,a1
bra.s gid_cont_ext
gid_not_ext move.l d7,-(sp)
moveq #0,d7
move.w d1,d7
divu #12,d7 ;octave #
move.l d7,d5
cmp.w #6,d7 ;if oct > 5, oct = 5
blt.s nohioct
moveq #5,d7
nohioct swap d5 ;note number in this oct (0-11) is in d5
move.l (a0),d1
cmp.w #6,d0
ble.s nounrecit
moveq #6,d0
nounrecit add.b gid_addtable-1(pc,d0.w),d7
move.b gid_divtable-1(pc,d0.w),d0
divu d0,d1 ;get length of the highest octave
swap d1
clr.w d1
swap d1
move.l d1,d0 ;d0 and d1 = length of the 1st oct
move.w inst_repeat(a3),d2
move.w inst_replen(a3),d3
moveq #0,d6
move.b shiftcnt(pc,d7.w),d6
lsl.w d6,d2
lsl.w d6,d3
lsl.w d6,d1
move.b mullencnt(pc,d7.w),d6
mulu d6,d0 ;offset of this oct from 1st oct
add.l a0,d0 ;add base address to offset
addq.l #6,d0 ;skip structure
add.l d0,d1
move.l a1,trk_periodtbl(a5)
add.b octstart(pc,d7.w),d5
add.b d5,d5
move.w 0(a1,d5.w),d5
move.l (sp)+,d7
bra.s gid_setrept
shiftcnt: dc.b 4,3,2,1,1,0,2,2,1,1,0,0,1,1,0,0,0,0
dc.b 3,3,2,2,1,0,5,4,3,2,1,0,6,5,4,3,2,1
mullencnt: dc.b 15,7,3,1,1,0,3,3,1,1,0,0,1,1,0,0,0,0
dc.b 7,7,3,3,1,0,31,15,7,3,1,0,63,31,15,7,3,1
octstart: dc.b 12,12,12,12,24,24,0,12,12,24,24,36,0,12,12,24,36,36
dc.b 0,12,12,24,24,24,12,12,12,12,12,12,12,12,12,12,12,12
ENDC
gid_setrept add.l d2,d2
add.l d0,d2 ;rep. start pointer
cmp.w #1,d3
bhi.s gid_noreplen2
moveq #0,d3 ;no repeat
bra.s gid_cont
gid_noreplen2 add.l d3,d3
add.l d2,d3 ;rep. end pointer
; -------- CALCULATE START/END ADDRESSES ---------------------------------
gid_cont moveq #0,d4
move.w trk_soffset(a5),d4
add.l d4,d0
cmp.l d0,d1
bhi.s pn_nooffsovf
sub.l d4,d0
pn_nooffsovf movea.l trk_audioaddr(a5),a1 ;base of this channel's regs
move.l d0,(a1)+ ;push ac_ptr
moveq #0,d4
move.b trk_previnstr(a5),d4
lea flags-DB(a6),a0
btst #0,0(a0,d4.w) ;test flags.SSFLG_LOOP
bne.s repeat
move.l #_chipzero,trk_sampleptr(a5) ;pointer of zero word
move.w #1,trk_samplelen(a5) ;length: 1 word
sub.l d0,d1
lsr.l #1,d1 ;shift length right
move.w d1,(a1)+ ;and push to ac_len
bra.s retsn1
repeat move.l d2,trk_sampleptr(a5)
move.l d3,d1
sub.l d0,d1
lsr.l #1,d1
move.w d1,(a1)+ ;ac_len
sub.l d2,d3
lsr.l #1,d3
move.w d3,trk_samplelen(a5)
retsn1 move.w d5,trk_prevper(a5)
IFNE SYNTH
tst.b trk_synthtype(a5)
bne.w hSn2
ENDC
pnote_rts rts
IFNE MIDI
; -------- MIDI NOTE PLAYER ROUTINE --------------------------------------
handleMIDInote:
IFNE PLAYMMD0
cmp.b #'1',3(a2)
bge.s plr_mmd1_3
add.b #24,d1
plr_mmd1_3
ENDC
; -------- CHECK & SCALE VOLUME ------------------------------------------
move.b trk_prevvol(a5),d2 ;temporarily save the volume
add.b d2,d2 ;volume 0 - 63 => 0 - 127
subq.b #1,d2 ;if 128 => 127
bpl.s hmn_notvolu0
moveq #0,d2
hmn_notvolu0
moveq #0,d5
; -------- CHECK MIDI CHANNEL --------------------------------------------
move.b inst_midich(a3),d5 ;get midi chan of this instrument
bpl.s hmn_nosmof ;bit 7 clear
clr.b trk_prevmidin(a5) ;suppress note off!
bra.s hmn_smof
hmn_nosmof move.b d1,trk_prevmidin(a5)
hmn_smof and.b #$1F,d5 ;clear all flag bits etc...
subq.b #1,d5 ;from 1-16 to 0-15
move.b d5,trk_prevmidich(a5) ;save to prev midi channel
; -------- CHECK MIDI PRESET ---------------------------------------------
moveq #0,d0
move.b trk_previnstr(a5),d0
add.w d0,d0
lea ext_midipsets-DB(a6),a1
move.w 0(a1,d0.w),d0 ;get preset #
beq.s nochgpres ;zero = no preset
lea prevmidicpres-DB(a6),a1
adda.w d5,a1
adda.w d5,a1
cmp.w (a1),d0 ;is this previous preset ??
beq.s nochgpres ;yes...no need to change
move.w d0,(a1) ;save preset to prevmidicpres
subq.w #1,d0 ;sub 1 to get 0 - 127
btst #6,inst_midich(a3)
bne.s hmn_extpreset
; -------- PREPARE PRESET CHANGE COMMAND ---------------------------------
hmn_ordpreset lea preschgdata+1-DB(a6),a0
move.b d0,(a0) ;push the number to second byte
moveq #2,d0
hmn_sendpreset move.b #$c0,-(a0) ;command: $C
or.b d5,(a0) ;"or" midi channel
move.w d1,-(sp)
bsr.w _AddMIDId
move.w (sp)+,d1
tst.b d2
beq.s hmn_suppress ;vol = 0, don't send NOTE ON
; -------- PREPARE & SEND NOTE ON COMMAND --------------------------------
nochgpres lea bytesinnotebuff-DB(a6),a0
movea.l a0,a1
adda.w (a0)+,a0
or.b #$90,d5 ;MIDI: Note on
move.b d5,(a0)+ ;MIDI msg Note on & channel
move.b d1,(a0)+ ;MIDI msg note #
move.b d2,(a0) ;MIDI msg volume
beq.s hmn_suppress ;vol = 0 -> no note
addq.w #3,(a1)
rts
hmn_suppress st trk_prevmidin(a5)
rts
; -------- HANDLE EXTENDED PRESET ----------------------------------------
hmn_extpreset cmp.w #100,d0
blt.s hmn_ordpreset
moveq #99,d3
hmn_loop100 sub.w #100,d0
addq.b #1,d3
cmp.w #100,d0
bge.s hmn_loop100
lea preschgdata+2-DB(a6),a0
move.b d0,(a0) ;push the <= 99 number
move.b d3,-(a0) ;push the >= 100 number
moveq #3,d0
bra.s hmn_sendpreset
ENDC
IFNE SYNTH
; -------- TRIGGER SYNTH NOTE, CLEAR PARAMETERS --------------------------
handleSynthnote move.b d1,trk_prevnote2(a5)
move.l a0,trk_synthptr(a5)
cmp.w #-2,4(a0) ;HYBRID??
bne.s hSn_nossn
st trk_synthtype(a5)
movea.l 278(a0),a0 ;yep, get the waveform pointer
bra.w tlwtst0 ;go and play it
hSn_nossn: move.b #1,trk_synthtype(a5)
lea _periodtable+32-DB(a6),a1
move.b trk_finetune(a5),d0 ;finetune value
add.b d0,d0
add.b d0,d0 ;multiple by 4...
ext.w d0 ;extend
movea.l 0(a1,d0.w),a1 ;period table address
suba.w #48,a1
move.l a1,trk_periodtbl(a5) ;save table ptr for synth periods
add.w d1,d1
move.w 0(a1,d1.w),d1
move.w d1,trk_prevper(a5)
clr.l trk_sampleptr(a5)
hSn2: lea trk_arpgoffs(a5),a1
clr.l (a1)+
clr.l (a1)+
clr.l (a1)+
clr.l (a1)+
clr.l (a1)+
clr.l (a1)+
move.l #sinetable,(a1)+
clr.w (a1)+
movea.l trk_synthptr(a5),a0
move.w 18(a0),(a1)+
clr.b (a1)
cmp.b #$E,trk_cmd(a5)
bne.s hSn_nocmdE
move.b trk_cmdqual(a5),trk_wfcmd+1(a5)
hSn_nocmdE moveq #64,d4
rts
synth_start move.w trk_prevper(a5),d5
synth_start2 move.l a3,-(sp) ;d0 = SynthPtr
move.l d0,a0
movea.l trk_audioaddr(a5),a3 ;audio channel base address
; -------- SYNTHSOUND VOLUME SEQUENCE HANDLING ---------------------------
subq.b #1,trk_volxcnt(a5) ;decrease execute counter..
bgt.w synth_wftbl ;not 0...go to waveform
move.b trk_initvolxspd(a5),trk_volxcnt(a5) ;reset counter
move.b trk_volchgspd(a5),d0 ;volume change??
beq.s synth_nochgvol ;no.
add.b trk_synvol(a5),d0 ;add previous volume
bpl.s synth_voln2l ;not negative
moveq #0,d0 ;was negative => 0
synth_voln2l cmp.b #$40,d0 ;too high??
ble.s synth_voln2h ;not 2 high.
moveq #$40,d0 ;was 2 high => 64
synth_voln2h move.b d0,trk_synvol(a5) ;remember new...
synth_nochgvol move.l trk_envptr(a5),d1 ;envelope pointer
beq.s synth_novolenv
movea.l d1,a1
move.b (a1)+,d0
add.b #128,d0
lsr.b #2,d0
move.b d0,trk_synvol(a5)
addq.b #1,trk_envcount(a5)
bpl.s synth_endenv
clr.b trk_envcount(a5)
move.l trk_envrestart(a5),a1
synth_endenv move.l a1,trk_envptr(a5)
synth_novolenv move.w trk_volcmd(a5),d0 ;get table position ptr
tst.b trk_volwait(a5) ;WAI(t) active
beq.s synth_getvolcmd ;no
subq.b #1,trk_volwait(a5) ;yep, decr wait ctr
ble.s synth_getvolcmd ;0 => continue
bra.w synth_wftbl ;> 0 => still wait
synth_inccnt addq.b #1,d0
synth_getvolcmd addq.b #1,d0 ;advance pointer
move.b 21(a0,d0.w),d1 ;get command
bmi.s synth_cmd ;negative = command
move.b d1,trk_synvol(a5) ;set synthvol
bra.w synth_endvol ;end of volume executing
synth_cmd and.w #$000f,d1
add.b d1,d1
move.w synth_vtbl(pc,d1.w),d1
jmp syv(pc,d1.w)
synth_vtbl dc.w syv_f0-syv,syv_f1-syv,syv_f2-syv,syv_f3-syv
dc.w syv_f4-syv,syv_f5-syv,syv_f6-syv
dc.w synth_endvol-syv,synth_endvol-syv,synth_endvol-syv
dc.w syv_fa-syv,syv_ff-syv,synth_endvol-syv
dc.w synth_endvol-syv,syv_fe-syv,syv_ff-syv
; -------- VOLUME SEQUENCE COMMANDS --------------------------------------
syv
syv_fe move.b 22(a0,d0.w),d0 ;JMP
bra.s synth_getvolcmd
syv_f0 move.b 22(a0,d0.w),trk_initvolxspd(a5) ;change volume ex. speed
bra.s synth_inccnt
syv_f1 move.b 22(a0,d0.w),trk_volwait(a5) ;WAI(t)
addq.b #1,d0
bra.s synth_endvol
syv_f3 move.b 22(a0,d0.w),trk_volchgspd(a5) ;set volume slide up
bra.s synth_inccnt
syv_f2 move.b 22(a0,d0.w),d1
neg.b d1
move.b d1,trk_volchgspd(a5) ;set volume slide down
bra.s synth_inccnt
syv_fa move.b 22(a0,d0.w),trk_wfcmd+1(a5) ;JWS (jump wform sequence)
clr.b trk_wfwait(a5)
bra.s synth_inccnt
syv_f4 move.b 22(a0,d0.w),d1
bsr.s synth_getwf
clr.l trk_envrestart(a5)
syv_f4end move.l a1,trk_envptr(a5)
clr.b trk_envcount(a5)
bra.w synth_inccnt
syv_f5 move.b 22(a0,d0.w),d1
bsr.s synth_getwf
move.l a1,trk_envrestart(a5)
bra.s syv_f4end
syv_f6 clr.l trk_envptr(a5)
bra.w synth_getvolcmd
synth_getwf ext.w d1 ;d1 = wform number, returns ptr in a1
add.w d1,d1 ;create index
add.w d1,d1
lea 278(a0),a1
adda.w d1,a1
movea.l (a1),a1 ;get wform address
addq.l #2,a1 ;skip length
rts
syv_ff subq.b #1,d0
synth_endvol move.w d0,trk_volcmd(a5)
synth_wftbl
IFNE RELVOL
moveq #0,d0
move.b trk_synvol(a5),d0
mulu trk_trackvol(a5),d0
lsr.w #8,d0
move.b d0,trk_prevvol(a5) ;vol of this instr
ENDC
IFEQ RELVOL
move.b trk_synvol(a5),trk_prevvol(a5)
ENDC
adda.w #158,a0
; -------- SYNTHSOUND WAVEFORM SEQUENCE HANDLING -------------------------
subq.b #1,trk_wfxcnt(a5) ;decr. wf speed counter
bgt.w synth_arpeggio ;not yet...
move.b trk_initwfxspd(a5),trk_wfxcnt(a5) ;restore speed counter
move.w trk_wfcmd(a5),d0 ;get table pos offset
move.w trk_wfchgspd(a5),d1 ;CHU/CHD ??
beq.s synth_tstwfwai ;0 = no change
wytanwet add.w trk_perchg(a5),d1 ;add value to current change
move.w d1,trk_perchg(a5) ;remember amount of change
synth_tstwfwai tst.b trk_wfwait(a5) ;WAI ??
beq.s synth_getwfcmd ;not waiting...
subq.b #1,trk_wfwait(a5) ;decr wait counter
beq.s synth_getwfcmd ;waiting finished
bra.w synth_arpeggio ;still sleep...
synth_incwfc addq.b #1,d0
synth_getwfcmd addq.b #1,d0 ;advance position counter
move.b -9(a0,d0.w),d1 ;get command
bmi.s synth_wfcmd ;negative = command
ext.w d1
add.w d1,d1
add.w d1,d1
movea.l 120(a0,d1.w),a1
move.w (a1)+,ac_len(a3) ;push waveform length
move.l a1,ac_ptr(a3) ;and the new pointer
bra.w synth_wfend ;no new commands now...
synth_wfcmd and.w #$000f,d1 ;get the right nibble
add.b d1,d1 ;* 2
move.w synth_wfctbl(pc,d1.w),d1
jmp syw(pc,d1.w) ;jump to command
synth_wfctbl dc.w syw_f0-syw,syw_f1-syw,syw_f2-syw,syw_f3-syw,syw_f4-syw
dc.w syw_f5-syw,syw_f6-syw,syw_f7-syw,synth_wfend-syw
dc.w synth_wfend-syw,syw_fa-syw,syw_ff-syw
dc.w syw_fc-syw,synth_getwfcmd-syw,syw_fe-syw,syw_ff-syw
; -------- WAVEFORM SEQUENCE COMMANDS ------------------------------------
syw
syw_f7 move.b -8(a0,d0.w),d1
ext.w d1
add.w d1,d1
add.w d1,d1
movea.l 120(a0,d1.w),a1
addq.l #2,a1
move.l a1,trk_synvibwf(a5)
bra.s synth_incwfc
syw_fe move.b -8(a0,d0.w),d0 ;jump (JMP)
bra.s synth_getwfcmd
syw_fc move.w d0,trk_arpsoffs(a5) ;new arpeggio begin
move.w d0,trk_arpgoffs(a5)
synth_findare addq.b #1,d0
tst.b -9(a0,d0.w)
bpl.s synth_findare
bra.s synth_getwfcmd
syw_f0 move.b -8(a0,d0.w),trk_initwfxspd(a5) ;new waveform speed
bra synth_incwfc
syw_f1 move.b -8(a0,d0.w),trk_wfwait(a5) ;wait waveform
addq.b #1,d0
bra.s synth_wfend
syw_f4 move.b -8(a0,d0.w),trk_synvibdep+1(a5) ;set vibrato depth
bra.w synth_incwfc
syw_f5 move.b -8(a0,d0.w),trk_synthvibspd+1(a5) ;set vibrato speed
addq.b #1,trk_synthvibspd+1(a5)
bra.w synth_incwfc
syw_f2 moveq #0,d1 ;set slide down
move.b -8(a0,d0.w),d1
synth_setsld move.w d1,trk_wfchgspd(a5)
bra.w synth_incwfc
syw_f3 move.b -8(a0,d0.w),d1 ;set slide up
neg.b d1
ext.w d1
bra.s synth_setsld
syw_f6 clr.w trk_perchg(a5) ;reset period
move.w trk_prevper(a5),d5
bra.w synth_getwfcmd
syw_fa move.b -8(a0,d0.w),trk_volcmd+1(a5) ;JVS (jump volume sequence)
clr.b trk_volwait(a5)
bra.w synth_incwfc
syw_ff subq.b #1,d0 ;pointer = END - 1
synth_wfend move.w d0,trk_wfcmd(a5)
; -------- HANDLE SYNTHSOUND ARPEGGIO ------------------------------------
synth_arpeggio move.w trk_arpgoffs(a5),d0
beq.s synth_vibrato
moveq #0,d1
move.b -8(a0,d0.w),d1
add.b trk_prevnote2(a5),d1
movea.l trk_periodtbl(a5),a1 ;get period table
add.w d1,d1
move.w 0(a1,d1.w),d5
addq.b #1,d0
tst.b -8(a0,d0.w)
bpl.s synth_noarpres
move.w trk_arpsoffs(a5),d0
synth_noarpres move.w d0,trk_arpgoffs(a5)
; -------- HANDLE SYNTHSOUND VIBRATO -------------------------------------
synth_vibrato move.w trk_synvibdep(a5),d1 ;get vibrato depth
beq.s synth_rts ;0 => no vibrato
move.w trk_synviboffs(a5),d0 ;get offset
lsr.w #4,d0 ;/ 16
and.w #$1f,d0 ;sinetable offset (0-31)
movea.l trk_synvibwf(a5),a0
move.b 0(a0,d0.w),d0 ;get a byte
ext.w d0 ;to word
muls d1,d0 ;amplify (* depth)
asr.w #8,d0 ;and divide by 64
add.w d0,d5 ;add vibrato...
move.w trk_synthvibspd(a5),d0 ;vibrato speed
add.w d0,trk_synviboffs(a5) ;add to offset
synth_rts add.w trk_perchg(a5),d5
cmp.w #113,d5 ;overflow??
bge.s synth_pern2h
moveq #113,d1
synth_pern2h move.l (sp)+,a3
rts
ENDC
sinetable dc.b 0,25,49,71,90,106,117,125,127,125,117,106,90,71,49
dc.b 25,0,-25,-49,-71,-90,-106,-117,-125,-127,-125,-117
dc.b -106,-90,-71,-49,-25,0
_IntHandler: movem.l d2-d7/a2-a6,-(sp)
IFNE CIAB|VBLANK
movea.l a1,a6 ;get data base address (int_Data)
ENDC
IFEQ CIAB|VBLANK
lea DB,a6 ;don't expect a1 to contain DB address
ENDC
tst.b bpmcounter-DB(a6)
bmi.s plr_nobpm
subq.b #1,bpmcounter-DB(a6)
ble.s plr_bpmcnt0
bra.w plr_exit
plr_bpmcnt0 move.b #4,bpmcounter-DB(a6)
plr_nobpm movea.l _module-DB(a6),a2
move.l a2,d0
beq.w plr_exit
IFNE MIDI
clr.b lastcmdbyte-DB(a6) ;no MIDI optimization
ENDC
tst.w mmd_pstate(a2)
beq.w plr_exit
IFNE MIDI
clr.l dmaonmsk-DB(a6)
ENDC
IFEQ MIDI
clr.w dmaonmsk-DB(a6)
ENDC
movea.l mmd_songinfo(a2),a4
moveq #0,d3
move.b mmd_counter(a2),d3
addq.b #1,d3
cmp.b msng_tempo2(a4),d3
bge.s plr_pnewnote ;play new note
move.b d3,mmd_counter(a2)
bne.w plr_fxtime ;do just fx
; --- new note!!
plr_pnewnote: clr.b mmd_counter(a2)
tst.w blkdelay-DB(a6)
beq.s plr_noblkdelay
subq.w #1,blkdelay-DB(a6)
bne.w nonewnote
; --- now start to play it
plr_noblkdelay move.w mmd_pblock(a2),d0
movea.l mmd_blockarr(a2),a0
add.w d0,d0
add.w d0,d0
movea.l 0(a0,d0.w),a1 ;block...
move.w mmd_pline(a2),d0
IFNE PLAYMMD0
cmp.b #'1',3(a2) ;check ID type
bge.s plr_mmd1_0
move.w d0,d1
add.w d0,d0
add.w d1,d0 ;d0 = d0 * 3
clr.l numtracks-DB(a6)
move.b (a1)+,numtracks+1-DB(a6)
move.b (a1),numlines+1-DB(a6)
mulu numtracks-DB(a6),d0
pea 1(a1,d0.w)
bra.s plr_begloop
plr_mmd1_0
ENDC
add.w d0,d0
add.w d0,d0 ;d0 = d0 * 4
mulu (a1),d0 ;numtracks * d0
pea 8(a1,d0.l) ;address of the current note
move.w (a1)+,numtracks-DB(a6)
move.w (a1),numlines-DB(a6)
plr_begloop moveq #0,d7 ;number of track
moveq #0,d4
pea trackdataptrs-DB(a6)
plr_loop0: moveq #0,d5
move.l (sp),a1
movea.l (a1)+,a5 ;get address of this track's struct
move.l a1,(sp)
; SPECIAL...
tst.w d7
bne.s skipch0_0
tst.w _freech0
bne.w plr_endloop0
skipch0_0
; END OF SPECIAL
; ---------------- get the note numbers
moveq #0,d3
move.l 4(sp),a1
IFNE PLAYMMD0
cmp.b #'1',3(a2)
bge.s plr_mmd1_1
move.b (a1)+,d5
move.b (a1)+,d6
move.b (a1)+,trk_cmdqual(a5)
move.b d6,d3
and.w #$0F,d6
lsr.b #4,d3
bclr #7,d5
beq.s plr_bseti4
bset #4,d3
plr_bseti4 bclr #6,d5
beq.s plr_bseti5
bset #5,d3
plr_bseti5 bra.s plr_nngok
plr_mmd1_1
ENDC
move.b (a1)+,d5 ;get the number of this note
bpl.s plr_nothinote
moveq #0,d5
plr_nothinote move.b (a1)+,d3 ;instrument number
move.b (a1)+,d6 ;cmd number
and.w #$1F,d6 ;recognize only cmds 00 - 1F
move.b (a1)+,trk_cmdqual(a5) ;databyte (qualifier)
plr_nngok move.l a1,4(sp)
; ---------------- check if there's an instrument number
and.w #$3F,d3
beq.s noinstnum
; ---------------- finally, save the number
subq.b #1,d3
move.b d3,trk_previnstr(a5) ;remember instr. number!
IFNE HOLD
lea holdvals-DB(a6),a0
adda.w d3,a0
move.b (a0),trk_inithold(a5)
move.b 63(a0),trk_initdecay(a5)
move.b 126(a0),trk_finetune(a5)
ENDC
IFEQ HOLD
lea finetunes-DB(a6),a0
move.b 0(a0,d3.w),trk_finetune(a5)
ENDC
asl.w #3,d3
lea 0(a4,d3.w),a3 ;a3 contains now address of it
move.l a3,trk_previnstra(a5)
moveq #0,d0
; ---------------- get volume and make it relative (1 - 100 %)
IFNE RELVOL
move.b inst_svol(a3),d0
mulu trk_trackvol(a5),d0
lsr.w #8,d0
move.b d0,trk_prevvol(a5) ;vol of this instr
ENDC
IFEQ RELVOL
move.b inst_svol(a3),trk_prevvol(a5)
ENDC
; ---------------- remember transpose
move.b inst_strans(a3),trk_stransp(a5)
clr.w trk_soffset(a5) ;sample offset
; ---------------- check the commands
noinstnum move.b d6,trk_cmd(a5) ;save the effect number
beq.w fx ;no effect
move.b trk_cmdqual(a5),d4 ;get qualifier...
add.b d6,d6 ;* 2
move.w f_table(pc,d6.w),d0
jmp fst(pc,d0.w)
f_table dc.w fx-fst,fx-fst,fx-fst,f_03-fst,fx-fst,fx-fst,fx-fst,fx-fst
dc.w f_08-fst,f_09-fst,fx-fst,f_0b-fst,f_0c-fst,fx-fst,f_0e-fst,f_0f-fst
dc.w fx-fst,fx-fst,fx-fst,fx-fst,fx-fst,f_15-fst,f_16-fst,fx-fst
dc.w fx-fst,f_19-fst,fx-fst,fx-fst,f_1c-fst,f_1d-fst,fx-fst,f_1f-fst
fst
; ---------------- tempo (F)
f_0f tst.b d4 ;test effect qual..
beq fx0fchgblck ;if effect qualifier (last 2 #'s)..
cmp.b #$f0,d4 ;..is zero, go to next block
bhi.s fx0fspecial ;if it's F1-FF something special
; ---------------- just an ordinary "change tempo"-request
IFNE CIAB
moveq #0,d0 ;will happen!!!
move.b d4,d0
move.w d0,msng_deftempo(a4)
bsr _SetTempo ;change The Tempo
ENDC
bra.w fx
; ---------------- no, it was FFx, something special will happen!!
fx0fspecial: cmp.b #$f2,d4
beq.s f_1f
cmp.b #$f4,d4
beq.s f_1f
cmp.b #$f5,d4
bne.s isfxfe
; ---------------- FF2 (or 1Fxx)
f_1f move.b d5,(a5) ; save the note number
moveq #0,d5 ; clear the number for awhile
IFNE HOLD
move.b trk_inithold(a5),trk_noteoffcnt(a5) ;initialize hold
bne.w plr_endloop0 ;not 0 -> OK
st trk_noteoffcnt(a5) ;0 -> hold = 0xff (-1)
ENDC
bra.w plr_endloop0
isfxfe: cmp.b #$fe,d4
bne.s notcmdfe
; ---------------- it was FFE, stop playing
clr.w mmd_pstate(a2)
IFNE CIAB
movea.l craddr-DB(a6),a0
bclr #0,(a0)
ENDC
bsr.w SoundOff
addq.l #8,sp
bra.w plr_exit
notcmdfe: cmp.b #$fd,d4 ;change period
bne.s isfxff
; ---------------- FFD, change the period, don't replay the note
IFNE CHECK
cmp.w #4,d7
bge.w fx
ENDC
movea.l trk_periodtbl(a5),a0
subq.b #1,d5
bmi.w plr_endloop0
add.b msng_playtransp(a4),d5
add.b trk_stransp(a5),d5
add.w d5,d5
bmi plr_endloop0
move.w 0(a0,d5.w),trk_prevper(a5)
moveq #0,d5
bra.w fx
isfxff: cmp.b #$ff,d4
bne.w fx
move.w d7,d0
bsr.w _ChannelOff
bra.w fx
; ---------------- F00, called Pattern Break in ST
fx0fchgblck: move.b #1,nextblock-DB(a6)
bra.w fx
; ---------------- was not Fxx
f_0e cmp.b #3,d7
bgt.w fx
move.b d4,trk_wfcmd+1(a5) ;set waveform command position ptr
bra.w fx
; ---------------- change volume
f_0c move.b d4,d0
bpl.s plr_nosetdefvol
and.b #$7F,d0
IFNE CHECK
cmp.b #64,d0
bgt.s go_nocmd
ENDC
moveq #0,d1
move.b trk_previnstr(a5),d1
asl.w #3,d1
move.b d0,inst_svol(a4,d1.w)
bra.s plr_setvol
plr_nosetdefvol btst #4,msng_flags(a4) ;look at flags
bne.s volhex
lsr.b #4,d0 ;get number from left
mulu #10,d0 ;number of tens
move.b d4,d1 ;get again
and.b #$0f,d1 ;this time don't get tens
add.b d1,d0 ;add them
volhex:
IFNE CHECK
cmp.b #64,d0
bhi.s go_nocmd
ENDC
plr_setvol
IFNE RELVOL
mulu trk_trackvol(a5),d0
lsr.w #8,d0
ENDC
move.b d0,trk_prevvol(a5)
go_nocmd bra.w fx
; ---------------- tempo2 change?
f_09
IFNE CHECK
and.b #$1F,d4
bne.s fx9chk
moveq #$20,d4
ENDC
fx9chk: move.b d4,msng_tempo2(a4)
bra fx
; ---------------- finetune
f_15
IFNE CHECK
cmp.b #7,d4
bgt fx
cmp.b #-8,d4
blt fx
ENDC
move.b d4,trk_finetune(a5)
bra fx
; ---------------- repeat loop
f_16 tst.b d4
bne.s plr_dorpt
move.w mmd_pline(a2),rptline-DB(a6)
bra fx
plr_dorpt tst.w rptcounter-DB(a6)
beq.s plr_newrpt
subq.w #1,rptcounter-DB(a6)
beq fx
bra.s plr_setrptline
plr_newrpt move.b d4,rptcounter+1-DB(a6)
plr_setrptline move.w rptline-DB(a6),d0
addq.w #1,d0
move.w d0,nextblockline-DB(a6)
bra fx
; ---------------- preset change
f_1c
IFNE CHECK
cmp.b #$80,d4
bhi fx
ENDC
moveq #0,d1
move.b trk_previnstr(a5),d1
add.w d1,d1
lea ext_midipsets-DB(a6),a0
ext.w d4
move.w d4,0(a0,d1.w) ;set MIDI preset
bra.s fx
; ---------------- note off time set??
f_08
IFNE HOLD
move.b d4,d0
lsr.b #4,d4 ;extract left nibble
and.b #$0f,d0 ; " " right " "
move.b d4,trk_initdecay(a5) ;left = decay
move.b d0,trk_inithold(a5) ;right = hold
ENDC
bra.s fx
; ---------------- sample begin offset
f_19 lsl.w #8,d4
move.w d4,trk_soffset(a5)
bra.s fx
; ---------------- cmd Bxx, "position jump"
f_0b
IFNE CHECK
cmp.b #'2',3(a2)
beq.s chk0b_mmd2
cmp.w msng_songlen(a4),d4
bhi.s fx
bra.s chk0b_end
chk0b_mmd2 move.w mmd_pseq(a2),d0 ;get seq number
movea.l msng_pseqs(a4),a1 ;ptr to playseqs
movea.l 0(a1,d0.w),a0 ;a0 = ptr to curr PlaySeq
cmp.w 40(a0),d4 ;test song length
bhi.s fx
chk0b_end
ENDC
move.w d4,mmd_pseqnum(a2)
st nextblock-DB(a6) ; = 1
bra.s fx
; ---------------- cmd 1Dxx, jump to next seq, line # specified
f_1d move.w #$1ff,nextblock-DB(a6)
addq.w #1,d4
move.w d4,nextblockline-DB(a6)
bra.s fx
; ---------------- try portamento (3)
f_03
IFNE CHECK
cmp.w #4,d7
bge.s plr_endloop0
ENDC
subq.b #1,d5 ;subtract note number
bmi.s plr_setfx3spd ;0 -> set new speed
plr_fx3note: movea.l trk_periodtbl(a5),a0
add.b msng_playtransp(a4),d5 ;play transpose
add.b trk_stransp(a5),d5 ;and instrument transpose
bmi.s plr_endloop0
add.w d5,d5
move.w 0(a0,d5.w),trk_porttrgper(a5) ;period of this note is the target
plr_setfx3spd: tst.b d4 ;qual??
beq.s plr_endloop0 ;0 -> do nothing
move.b d4,trk_prevportspd(a5) ;store speed
bra.s plr_endloop0 ;don't play this one
; ---------------- play or not to play??
fx tst.b d5 ;play a note?
beq.s plr_endloop0 ;no.
; ---------------- play
move.b d5,(a5)
move.w d5,d1
moveq #0,d3
move.b trk_previnstr(a5),d3 ;instr #
movea.l trk_previnstra(a5),a3 ;instr data address
IFNE HOLD
move.b trk_inithold(a5),trk_noteoffcnt(a5) ;initialize hold
bne.s plr_nohold0 ;not 0 -> OK
st trk_noteoffcnt(a5) ;0 -> hold = 0xff (-1)
ENDC
; ---------------- and finally:
plr_nohold0 bsr _PlayNote
; ---------------- end of loop: handle next track, or quit
plr_endloop0: addq.b #1,d7
cmp.w numtracks-DB(a6),d7
blt.w plr_loop0
addq.l #8,sp ;trackdataptrs / note ptr
; and advance song pointers
lea nextblock-DB(a6),a3
move.w nextblockline-DB(a6),d1
beq.s plr_advlinenum
clr.w nextblockline-DB(a6)
subq.w #1,d1
bra.s plr_linenumset
plr_advlinenum move.w mmd_pline(a2),d1 ;get current line #
addq.w #1,d1 ;advance line number
plr_linenumset cmp.w numlines-DB(a6),d1 ;advance block?
bhi.s plr_chgblock ;yes.
tst.b (a3) ;command F00/1Dxx?
beq plr_nochgblock ;no, don't change block
; -------- CHANGE BLOCK? -------------------------------------------------
plr_chgblock tst.b nxtnoclrln-DB(a6)
bne.s plr_noclrln
moveq #0,d1 ;clear line number
plr_noclrln tst.w mmd_pstate(a2) ;play block or play song
bpl plr_nonewseq ;play block only...
cmp.b #'2',3(a2) ;MMD2?
bne.s plr_noMMD2_0
; ********* BELOW CODE FOR MMD2 ONLY ************************************
; -------- CHANGE SEQUENCE -----------------------------------------------
plr_skipseq move.w mmd_pseq(a2),d0 ;actually stored as << 2
movea.l msng_pseqs(a4),a1
movea.l 0(a1,d0.w),a0
move.w mmd_pseqnum(a2),d0 ;get play sequence number
tst.b (a3)
bmi.s plr_noadvseq ;Bxx sets nextblock to -1
addq.w #1,d0 ;advance sequence number
plr_noadvseq cmp.w 40(a0),d0 ;is this the highest seq number??
blt.s plr_notagain ;no.
; -------- CHANGE SECTION ------------------------------------------------
move.w mmd_psecnum(a2),d0 ;get section number
addq.w #1,d0 ;increase..
cmp.w msng_songlen(a4),d0 ;highest section?
blt.s plr_nohisec
moveq #0,d0 ;yes.
plr_nohisec move.w d0,mmd_psecnum(a2) ;push back.
add.w d0,d0
movea.l msng_sections(a4),a0 ;section table
move.w 0(a0,d0.w),d0 ;new playseqlist number
add.w d0,d0
add.w d0,d0
move.w d0,mmd_pseq(a2)
movea.l 0(a1,d0.w),a0 ;a0 = ptr to new PlaySeq
moveq #0,d0 ;playseq OFFSET = 0
; -------- FETCH BLOCK NUMBER FROM SEQUENCE ------------------------------
plr_notagain move.w d0,mmd_pseqnum(a2) ;remember new playseq pos
add.w d0,d0
move.w 42(a0,d0.w),d0 ;get number of the block
bpl.s plr_changeblk ;neg. values for future expansion
bra.s plr_skipseq ;(skip them)
; ********* BELOW CODE FOR MMD0/MMD1 ONLY *******************************
plr_noMMD2_0 move.w mmd_pseqnum(a2),d0 ;get play sequence number
tst.b (a3)
bmi.s plr_noadvseq_b ;Bxx sets nextblock to -1
addq.w #1,d0 ;advance sequence number
plr_noadvseq_b cmp.w msng_songlen(a4),d0 ;is this the highest seq number??
blt.s plr_notagain_b ;no.
moveq #0,d0 ;yes: restart song
plr_notagain_b move.b d0,mmd_pseqnum+1(a2) ;remember new playseq-#
lea msng_playseq(a4),a0 ;offset of sequence table
move.b 0(a0,d0.w),d0 ;get number of the block
; ********* BELOW CODE FOR BOTH FORMATS *********************************
plr_changeblk
IFNE CHECK
cmp.w msng_numblocks(a4),d0 ;beyond last block??
blt.s plr_nolstblk ;no..
moveq #0,d0 ;play block 0
ENDC
plr_nolstblk move.w d0,mmd_pblock(a2) ;store block number
plr_nonewseq clr.w (a3) ;clear this if F00 set it
plr_nochgblock move.w d1,mmd_pline(a2) ;set new line number
IFNE HOLD
lea trackdataptrs-DB(a6),a5
movea.l mmd_blockarr(a2),a0
move.w mmd_pblock(a2),d0
add.w d0,d0
add.w d0,d0
movea.l 0(a0,d0.w),a1 ;block...
move.w mmd_pline(a2),d0
move.b msng_tempo2(a4),d3 ;interrupts/note
IFNE PLAYMMD0
cmp.b #'1',3(a2)
bge.s plr_mmd1_2
move.b (a1),d7 ;# of tracks
move.w d0,d1
add.w d0,d0 ;d0 * 2
add.w d1,d0 ;+ d0 = d0 * 3
mulu d7,d0
lea 2(a1,d0.w),a3
subq.b #1,d7
plr_chkholdb movea.l (a5)+,a1 ;track data
tst.b trk_noteoffcnt(a1) ;hold??
bmi.s plr_holdendb ;no.
move.b (a3),d1 ;get the 1st byte..
bne.s plr_hold1b
move.b 1(a3),d1
and.b #$f0,d1
beq.s plr_holdendb ;don't hold
bra.s plr_hold2b
plr_hold1b and.b #$3f,d1 ;note??
beq.s plr_hold2b ;no, cont hold..
move.b 1(a3),d1
and.b #$0f,d1 ;get cmd
subq.b #3,d1 ;is there command 3 (slide)
bne.s plr_holdendb ;no -> end holding
plr_hold2b add.b d3,trk_noteoffcnt(a1) ;continue holding...
plr_holdendb addq.l #3,a3 ;next note
dbf d7,plr_chkholdb
bra.s nonewnote
plr_mmd1_2
ENDC
move.w (a1),d7 ;# of tracks
add.w d0,d0
add.w d0,d0 ;d0 = d0 * 4
mulu d7,d0
lea 8(a1,d0.l),a3
subq.b #1,d7
plr_chkhold movea.l (a5)+,a1 ;track data
tst.b trk_noteoffcnt(a1) ;hold??
bmi.s plr_holdend ;no.
move.b (a3),d1 ;get the 1st byte..
bne.s plr_hold1
move.b 1(a3),d0
and.b #$3F,d0
beq.s plr_holdend ;don't hold
bra.s plr_hold2
plr_hold1 and.b #$7f,d1 ;note??
beq.s plr_hold2 ;no, cont hold..
move.b 2(a3),d1
subq.b #3,d1 ;is there command 3 (slide)
bne.s plr_holdend ;no -> end holding
plr_hold2 add.b d3,trk_noteoffcnt(a1) ;continue holding...
plr_holdend addq.l #4,a3 ;next note
dbf d7,plr_chkhold
ENDC
nonewnote
; SPECIAL... A GOOD PLACE FOR OWN HOOKS
moveq #0,d3
move.b mmd_counter(a2),d3
plr_fxtime lea trackdataptrs-DB(a6),a3
moveq #0,d7 ;clear track count
plr_loop1 movea.l (a3)+,a5
; SPECIAL...
tst.w d7
bne.s skipch0_1
tst.w _freech0
bne.w endl
skipch0_1
; END OF SPECIAL
moveq #0,d4
moveq #0,d5
moveq #0,d6
move.b trk_cmd(a5),d6 ;get the fx number
move.b trk_cmdqual(a5),d4 ;and the last 2 #'s
IFNE MIDI
tst.b trk_prevmidin(a5) ;is it MIDI??
bne.w midicmds
ENDC
cmp.w #4,d7
IFNE MIDI
bge.w midicmds ;no non-MIDI effects in tracks >= 4
ENDC
IFEQ MIDI
bge.w endl
ENDC
IFNE HOLD
tst.b trk_noteoffcnt(a5)
bmi.s plr_nowaitoff
subq.b #1,trk_noteoffcnt(a5)
bpl.s plr_nowaitoff
IFNE SYNTH
tst.b trk_synthtype(a5) ;synth/hybrid??
beq.s plr_nosyndec
move.b trk_decay(a5),trk_volcmd+1(a5) ;set volume command pointer
clr.b trk_volwait(a5) ;abort WAI
bra.s plr_nowaitoff
ENDC
plr_nosyndec: move.b trk_decay(a5),trk_fadespd(a5) ;set fade...
bne.s plr_nowaitoff ;if > 0, don't stop sound
bset d7,d5
move.w d5,$dff096 ;shut DMA...
moveq #0,d5
ENDC
plr_nowaitoff:
IFNE HOLD
move.b trk_fadespd(a5),d0 ;fade??
beq.s plr_nofade ;no.
sub.b d0,trk_prevvol(a5)
bpl.s plr_nofade
clr.b trk_prevvol(a5)
clr.b trk_fadespd(a5) ;fade no more
ENDC
plr_nofade add.b d6,d6 ;* 2
move.w fx_table(pc,d6.w),d0
jmp fxs(pc,d0.w)
fx_table dc.w fx_00-fxs,fx_01-fxs,fx_02-fxs,fx_03-fxs,fx_04-fxs
dc.w fx_05-fxs,fx_06-fxs,fx_07-fxs,fx_xx-fxs,fx_xx-fxs
dc.w fx_0a-fxs,fx_xx-fxs,fx_xx-fxs,fx_0d-fxs,fx_xx-fxs
dc.w fx_0f-fxs
dc.w fx_10-fxs,fx_11-fxs,fx_12-fxs,fx_13-fxs,fx_14-fxs
dc.w fx_xx-fxs,fx_xx-fxs,fx_xx-fxs,fx_18-fxs,fx_xx-fxs
dc.w fx_1a-fxs,fx_1b-fxs,fx_xx-fxs,fx_xx-fxs,fx_1e-fxs
dc.w fx_1f-fxs
fxs:
; **************************************** Effect 01 ******
fx_01: tst.b d3
bne.s fx_01nocnt0
btst #5,msng_flags(a4) ;FLAG_STSLIDE??
bne fx_xx
fx_01nocnt0 sub.w d4,trk_prevper(a5)
move.w trk_prevper(a5),d5
cmp.w #113,d5
bge plr_newper
move.w #113,d5
move.w d5,trk_prevper(a5)
bra plr_newper
; **************************************** Effect 11 ******
fx_11 tst.b d3
bne fx_xx
sub.w d4,trk_prevper(a5)
move.w trk_prevper(a5),d5
bra plr_newper
; **************************************** Effect 02 ******
fx_02: tst.b d3
bne.s fx_02nocnt0
btst #5,msng_flags(a4)
bne fx_xx
fx_02nocnt0 add.w d4,trk_prevper(a5)
move.w trk_prevper(a5),d5
bra.w plr_newper
; **************************************** Effect 12 ******
fx_12 tst.b d3
bne fx_xx
add.w d4,trk_prevper(a5)
move.w trk_prevper(a5),d5
bra plr_newper
; **************************************** Effect 00 ******
fx_00: tst.b d4 ;both fxqualifiers are 0s: no arpeggio
beq.w fx_xx
move.l d3,d0
divu #3,d0
swap d0
tst.w d0
bne.s fx_arp12
and.b #$0f,d4
add.b (a5),d4
bra.s fx_doarp
fx_arp12: subq.b #1,d0
bne.s fx_arp2
lsr.b #4,d4
add.b (a5),d4
bra.s fx_doarp
fx_arp2: move.b (a5),d4
fx_doarp: subq.b #1,d4 ;-1 to make it 0 - 127
add.b msng_playtransp(a4),d4 ;add play transpose
add.b trk_stransp(a5),d4 ;add instrument transpose
add.b d4,d4
movea.l trk_periodtbl(a5),a1
move.w 0(a1,d4.w),d5
bra.w plr_newtmp
; **************************************** Effect 04 ******
fx_14 move.b #6,trk_vibshift(a5)
bra.s vib_cont
fx_04 move.b #5,trk_vibshift(a5)
vib_cont tst.b d3
bne.s nonvib
move.b d4,d1
beq.s nonvib
and.w #$0f,d1
beq.s plr_chgvibspd
move.w d1,trk_vibrsz(a5)
plr_chgvibspd: and.b #$f0,d4
beq.s nonvib
lsr.b #3,d4
and.b #$3e,d4
move.b d4,trk_vibrspd(a5)
nonvib: move.b trk_vibroffs(a5),d0
lsr.b #2,d0
and.w #$1f,d0
moveq #0,d1
lea sinetable(pc),a0
move.b 0(a0,d0.w),d5
ext.w d5
muls trk_vibrsz(a5),d5
move.b trk_vibshift(a5),d1
asr.w d1,d5
add.w trk_prevper(a5),d5
move.b trk_vibrspd(a5),d0
add.b d0,trk_vibroffs(a5)
bra.w plr_newtmp
; **************************************** Effect 06 ******
fx_06: tst.b d3
bne.s fx_06nocnt0
btst #5,msng_flags(a4)
bne fx_xx
fx_06nocnt0 bsr.s plr_volslide ;Volume slide
bra.s nonvib ;+ Vibrato
; **************************************** Effect 07 ******
fx_07 tst.b d3
bne.s nontre
move.b d4,d1
beq.s nontre
and.w #$0f,d1
beq.s plr_chgtrespd
move.w d1,trk_tremsz(a5)
plr_chgtrespd and.b #$f0,d4
beq.s nonvib
lsr.b #2,d4
and.b #$3e,d4
move.b d4,trk_tremspd(a5)
nontre move.b trk_tremoffs(a5),d0
lsr.b #3,d0
and.w #$1f,d0
moveq #0,d1
lea sinetable(pc),a0
move.b 0(a0,d0.w),d5
ext.w d5
muls trk_tremsz(a5),d5
asr.w #7,d5
move.b trk_tremspd(a5),d0
add.b d0,trk_tremoffs(a5)
move.b trk_prevvol(a5),d1
add.b d5,d1
bpl.s tre_pos
moveq #0,d1
tre_pos cmp.b #64,d1
ble.s tre_no2hi
moveq #64,d1
tre_no2hi move.b d1,trk_tempvol(a5)
bra.w fx_xx
; **************************************** Effect 0D/0A ***
fx_0a:
fx_0d: tst.b d3
bne.s fx_0dnocnt0
btst #5,msng_flags(a4)
bne fx_xx
fx_0dnocnt0 bsr.s plr_volslide
bra fx_xx
; ********* VOLUME SLIDE FUNCTION *************************
plr_volslide move.b d4,d0
moveq #0,d1
move.b trk_prevvol(a5),d1 ;move previous vol to d1
and.b #$f0,d0
bne.s crescendo
sub.b d4,d1 ;sub from prev. vol
voltest0 bpl.s novolover64
moveq #0,d1 ;volumes under zero not accepted!!!
bra.s novolover64
crescendo: lsr.b #4,d0
add.b d0,d1
voltest cmp.b #64,d1
ble.s novolover64
moveq #64,d1
novolover64 move.b d1,trk_prevvol(a5)
rts
; **************************************** Effect 1A ******
fx_1a tst.b d3
bne fx_xx
move.b trk_prevvol(a5),d1
add.b d4,d1
bsr.s voltest
bra fx_xx
; **************************************** Effect 1B ******
fx_1b tst.b d3
bne fx_xx
move.b trk_prevvol(a5),d1
sub.b d4,d1
bsr.s voltest0
bra fx_xx
; **************************************** Effect 05 ******
fx_05: tst.b d3
bne.s fx_05nocnt0
btst #5,msng_flags(a4)
bne fx_xx
fx_05nocnt0 bsr.s plr_volslide ;Volume slide
bra.s fx_03nocnt0
; **************************************** Effect 03 ******
fx_03: tst.b d3
bne.s fx_03nocnt0
btst #5,msng_flags(a4)
bne fx_xx
fx_03nocnt0 move.w trk_porttrgper(a5),d0 ;d0 = target period
beq.w fx_xx ;no target period specified
move.w trk_prevper(a5),d1 ;d1 = curr. period
move.b trk_prevportspd(a5),d4 ;get prev. speed
cmp.w d0,d1
bhi.s subper ;curr. period > target period
add.w d4,d1 ;add the period
cmp.w d0,d1
bge.s targreached
bra.s targnreach
subper: sub.w d4,d1 ;subtract
cmp.w d0,d1 ;compare current period to target period
bgt.s targnreach
targreached: move.w trk_porttrgper(a5),d1 ;eventually push target period
clr.w trk_porttrgper(a5) ;now we can forget everything
targnreach: move.w d1,trk_prevper(a5)
move.w d1,d5
bra.s plr_newper
; **************************************** Effect 13 ******
fx_13: move.w trk_prevper(a5),d5 ;this is very simple: get the old period
cmp.b #3,d3 ;and..
bge.s plr_newper ;if counter < 3
sub.w d4,d5 ;subtract effect qualifier
bra.s plr_newper
; **************************************** Effect 10 ******
fx_10:
IFNE MIDI
tst.b d3
bne.s fx_xx
move.w d4,d0
bsr.w _InitMIDIDump
ENDC
bra.s fx_xx
; **************************************** Effect 1E ******
fx_1e tst.w blkdelay-DB(a6)
bne.s fx_xx
addq.w #1,d4
move.w d4,blkdelay-DB(a6)
bra.s fx_xx
; **************************************** Effect 18 ******
fx_18 cmp.b d4,d3
bne.s fx_xx
clr.b trk_prevvol(a5)
bra.s fx_xx
; **************************************** Effect 1F ******
fx_1f move.b d4,d1
lsr.b #4,d4 ;note delay
beq.s nonotedelay
cmp.b d4,d3 ;compare to counter
blt.s fx_xx ;tick not reached
bne.s nonotedelay
bsr playfxnote ;trigger note
nonotedelay and.w #$0f,d1 ;retrig?
beq.s fx_xx
moveq #0,d0
move.b d3,d0
divu d1,d0
swap d0 ;get modulo of counter/tick
tst.w d0
bne.s fx_xx
bsr playfxnote ;retrigger
bra.s fx_xx
; **************************************** Effect 0F ******
fx_0f bsr cmd_F
; *********************************************************
plr_newper
fx_xx
IFNE SYNTH
move.l trk_synthptr(a5),d0
beq.s plr_nosynth
bsr.w synth_start
bra.s plr_tmpper
plr_newtmp move.l trk_synthptr(a5),d0
beq.s plr_tmpper
bsr.w synth_start2
bra.s plr_tmpper
ENDC
plr_nosynth move.w trk_prevper(a5),d5
IFEQ SYNTH
plr_newtmp
ENDC
plr_tmpper movea.l trk_audioaddr(a5),a1 ;get channel address
move.w d5,ac_per(a1) ;push period
beq.s endl
move.b trk_tempvol(a5),d0
bmi.s plr_notmpvol
move.b d0,ac_vol+1(a1)
st trk_tempvol(a5)
bra.s endl
plr_notmpvol move.b trk_prevvol(a5),ac_vol+1(a1) ;get volume & push it
endl: addq.b #1,d7 ;increment channel number
cmp.w numtracks-DB(a6),d7 ;all channels done???
blt.w plr_loop1 ;not yet!!!
plr_endfx: ;turn on DMA
move.w dmaonmsk-DB(a6),d0 ;dmaonmsk contains the mask of
IFNE MIDI
beq.s sdma_nodmaon ;the channels that must be turned on
ENDC
IFEQ MIDI
beq.s plr_exit
ENDC
bset #15,d0 ;DMAF_SETCLR: set these bits in dmacon
moveq #80,d1
; The following line makes the playroutine one scanline slower. If your
; song works well without the following instruction, you can leave it out.
IFNE SYNTH
add.w d1,d1 ;sometimes double wait time is required
ENDC
bsr.s _Wait1line
move.w d0,$dff096 ;do that!!!
moveq #80,d1
bsr.s _Wait1line
lea trackdataptrs-DB(a6),a1
bsr.s pushnewvals
bsr.s pushnewvals
bsr.s pushnewvals
bsr.s pushnewvals
IFNE MIDI
sdma_nodmaon lea bytesinnotebuff-DB(a6),a0
move.w (a0)+,d0
beq.s plr_exit
bsr.w _AddMIDId
ENDC
plr_exit: movem.l (sp)+,d2-d7/a2-a6
moveq #1,d0
rts
_Wait1line: move.w d0,-(sp) ;d1 = vsync counters to wait - 1
wl0: move.b $dff007,d0
wl1: cmp.b $dff007,d0
beq.s wl1
dbf d1,wl0
move.w (sp)+,d0
rts
pushnewvals: movea.l (a1)+,a5
lsr.b #1,d0
bcc.s rpnewv
move.l trk_sampleptr(a5),d1
beq.s rpnewv
movea.l trk_audioaddr(a5),a0
move.l d1,ac_ptr(a0)
move.w trk_samplelen(a5),ac_len(a0)
rpnewv: rts
cmd_F cmp.b #$f1,d4
bne.s no0ff1
cmp.b #3,d3
beq.s playfxnote
rts
no0ff1: cmp.b #$f2,d4
bne.s no0ff2
cmp.b #3,d3
beq.s playfxnote
rts
no0ff2: cmp.b #$f3,d4
bne.s no0ff3
move.b d3,d0
beq.s cF_rts
and.b #1,d0 ;is 2 or 4
bne.s cF_rts
playfxnote: moveq #0,d1
move.b (a5),d1 ;get note # of previous note
beq.s cF_rts
move.b trk_noteoffcnt(a5),d0 ;get hold counter
bmi.s pfxn_nohold ;no hold, or hold over
add.b d3,d0 ;increase by counter val
bra.s pfxn_hold
pfxn_nohold move.b trk_inithold(a5),d0 ;get initial hold
bne.s pfxn_hold
st d0
pfxn_hold move.b d0,trk_noteoffcnt(a5)
movem.l d3/a3,-(sp)
moveq #0,d3
move.b trk_previnstr(a5),d3 ;and prev. sample #
movea.l trk_previnstra(a5),a3
bsr _PlayNote
movem.l (sp)+,d3/a3
cF_rts rts
no0ff3: cmp.b #$f4,d4 ;triplet cmd 1
bne.s no0ff4
moveq #0,d0
move.b msng_tempo2(a4),d0
divu #3,d0
cmp.b d0,d3
beq.s playfxnote
rts
no0ff4 cmp.b #$f5,d4 ;triplet cmd 2
bne.s no0ff5
moveq #0,d0
move.b msng_tempo2(a4),d0
divu #3,d0
add.w d0,d0
cmp.b d0,d3
beq.s playfxnote
rts
no0ff5 cmp.b #$f8,d4 ;f8 = filter off
beq.s plr_filteroff
cmp.b #$f9,d4 ;f9 = filter on
bne.s cF_rts
bclr #1,$bfe001
rts
plr_filteroff: bset #1,$bfe001
rts
_SetTempo:
IFNE CIAB
move.l _module-DB(a6),d1
beq.s ST_x
move.l d1,a0
movea.l mmd_songinfo(a0),a0
btst #5,msng_flags2(a0)
bne.s ST_bpm
cmp.w #10,d0 ;If tempo <= 10, use SoundTracker tempo
bhi.s calctempo
subq.b #1,d0
add.w d0,d0
move.w sttempo+2(pc,d0.w),d1
bra.s pushtempo
calctempo: move.l timerdiv-DB(a6),d1
divu d0,d1
pushtempo: movea.l craddr+4-DB(a6),a0
move.b d1,(a0) ;and set the CIA timer
lsr.w #8,d1
movea.l craddr+8-DB(a6),a0
move.b d1,(a0)
ENDC
ST_x rts ; vv-- These values are the SoundTracker tempos (approx.)
sttempo: dc.w $0f00
IFNE CIAB
dc.w 2417,4833,7250,9666,12083,14500,16916,19332,21436,24163
ST_bpm move.b msng_flags2(a0),d1
and.w #$1F,d1
addq.b #1,d1
mulu d1,d0
move.l bpmdiv-DB(a6),d1
divu d0,d1
bra.s pushtempo
ENDC
IFNE MIDI
midicmds
IFNE HOLD
tst.b trk_noteoffcnt(a5)
bmi.s midi_nowaitoff
subq.b #1,trk_noteoffcnt(a5)
bpl.s midi_nowaitoff
move.l a5,a1
move.b trk_prevmidin(a5),d1
beq.s midi_nowaitoff ;no note
lea noteondata-DB(a6),a0
bsr.w choff_midi
midi_nowaitoff:
ENDC
add.b d6,d6 ;* 2
move.w midicmd_table(pc,d6.w),d0
jmp midifx(pc,d0.w)
midicmd_table: dc.w mfx_00-midifx,mfx_01-midifx,mfx_02-midifx,mfx_03-midifx,mfx_04-midifx
dc.w mfx_05-midifx,endl-midifx,endl-midifx,endl-midifx,endl-midifx
dc.w mfx_0a-midifx,endl-midifx,endl-midifx,mfx_0d-midifx,mfx_0e-midifx
dc.w mfx_0f-midifx
dc.w mfx_10-midifx,endl-midifx,endl-midifx,mfx_13-midifx
dc.w endl-midifx,endl-midifx,endl-midifx,mfx_17-midifx
dc.w endl-midifx,endl-midifx,endl-midifx,endl-midifx
dc.w endl-midifx,endl-midifx,endl-midifx,mfx_1f-midifx
midifx
mfx_01 lea prevmidipbend-DB(a6),a0
moveq #0,d1
move.b trk_prevmidich(a5),d1 ;get previous midi channel
add.b d1,d1 ;UWORD index
tst.b d4 ;x100??
beq.s resetpbend
move.w 0(a0,d1.w),d0 ;get previous pitch bend
lsl.w #3,d4 ;multiply bend value by 8
add.w d4,d0
cmp.w #$3fff,d0
bls.s bendpitch
move.w #$3fff,d0
bendpitch: move.w d0,0(a0,d1.w) ;save current pitch bend
lsr.b #1,d1 ;back to UBYTE
or.b #$e0,d1
lea noteondata-DB(a6),a0
move.b d1,(a0) ;midi command & channel
move.b d0,1(a0) ;lower value
and.b #$7f,1(a0) ;clear bit 7
lsr.w #7,d0
and.b #$7f,d0 ;clr bit 7
move.b d0,2(a0) ;higher 7 bits
moveq #3,d0
bsr.w _AddMIDId
bra.w endl
mfx_02 lea prevmidipbend-DB(a6),a0
moveq #0,d1
move.b trk_prevmidich(a5),d1
add.b d1,d1
tst.b d4
beq.s resetpbend ;x200??
move.w 0(a0,d1.w),d0
lsl.w #3,d4
sub.w d4,d0
bpl.s bendpitch ;not under 0
moveq #0,d0
bra.s bendpitch
resetpbend: tst.b d3 ;d3 = counter (remember??)
bne.w endl
move.w #$2000,d0
bra.s bendpitch
mfx_13
mfx_03 tst.b d3
bne.w endl
lea prevmidipbend-DB(a6),a0
moveq #0,d1
move.b trk_prevmidich(a5),d1
add.b d1,d1
move.b d4,d0
add.b #128,d0
lsl.w #6,d0
bra.s bendpitch
mfx_0d tst.b d3
bne.w endl
lea noteondata+1-DB(a6),a0 ;CHANNEL AFTERTOUCH
move.b d4,(a0) ;value
bmi.w endl
move.b trk_prevmidich(a5),-(a0)
or.b #$d0,(a0)
moveq #2,d0
bsr.w _AddMIDId
bra.w endl
mfx_0a tst.b d3
bne.w endl
lea noteondata+2-DB(a6),a0 ;POLYPHONIC AFTERTOUCH
and.b #$7f,d4
move.b d4,(a0)
move.b trk_prevmidin(a5),-(a0)
ble.w endl
move.b trk_prevmidich(a5),-(a0)
or.b #$A0,(a0)
moveq #3,d0
bsr.w _AddMIDId
bra.w endl
mfx_17 moveq #$07,d0 ;07 = VOLUME
bra.s pushctrldata
mfx_04 moveq #$01,d0 ;01 = MODULATION WHEEL
bra.s pushctrldata
mfx_0e moveq #$0a,d0
pushctrldata tst.b d3 ;do it only once in a note
bne.w endl ;(when counter = 0)
lea noteondata+2-DB(a6),a0 ;push "control change" data,
move.b d4,(a0) ;second databyte
bmi.w endl ;$0 - $7F only
move.b d0,-(a0) ;1st databyte
move.b trk_prevmidich(a5),-(a0) ;MIDI channel
or.b #$b0,(a0) ;command (B)
moveq #3,d0
bsr.w _AddMIDId
bra.w endl
mfx_05 and.b #$7f,d4 ;set contr. value of curr. MIDI ch.
move.b trk_prevmidich(a5),d6
lea midicontrnum-DB(a6),a0
adda.w d6,a0
move.b d4,(a0)
bra.w endl
mfx_0f cmp.b #$fa,d4 ;hold pedal ON
bne.s nomffa
moveq #$40,d0
moveq #$7f,d4
bra.s pushctrldata
nomffa cmp.b #$fb,d4 ;hold pedal OFF
bne.s mfx_0f_2
moveq #$40,d0
moveq #$00,d4
bra.s pushctrldata
mfx_0f_2 bsr.w cmd_F
bra.w endl
mfx_00 tst.b d4
beq.w endl
and.b #$7f,d4
move.b trk_prevmidich(a5),d6
lea midicontrnum-DB(a6),a0
move.b 0(a0,d6.w),d0
bra.s pushctrldata
mfx_10 tst.b d3
bne.w endl
move.w d4,d0
bsr.w _InitMIDIDump
bra.w endl
mfx_1f move.b d4,d1
lsr.b #4,d4 ;note delay
beq.s nonotedelay_m
cmp.b d4,d3 ;compare to counter
blt endl ;tick not reached
bne.s nonotedelay_m
bsr playfxnote ;trigger note
nonotedelay_m and.w #$0f,d1 ;retrig?
beq endl
moveq #0,d0
move.b d3,d0
divu d1,d0
swap d0 ;get modulo of counter/tick
tst.w d0
bne endl
bsr playfxnote ;retrigger
bra endl
_ResetMIDI: movem.l d2/a2/a6,-(sp)
movea.l 4.w,a6 ;ExecBase
jsr -$78(a6) ;Disable()
lea DB,a6
; Clear preset memory
lea prevmidicpres-DB(a6),a0
moveq #7,d2
RM_loop0 clr.l (a0)+ ;force presets to be set again
dbf d2,RM_loop0
clr.b lastcmdbyte
; Reset pitchbenders & modulation wheels
lea midiresd-DB(a6),a2
move.b #$e0,(a2)
move.b #$b0,3(a2)
moveq #15,d2
respbendl: movea.l a2,a0
moveq #6,d0
bsr.w _AddMIDId
addq.b #1,(a2)
addq.b #1,3(a2)
dbf d2,respbendl
lea prevmidipbend-DB(a6),a2
moveq #15,d2
resprevpbends: move.w #$2000,(a2)+
dbf d2,resprevpbends
; Clear dump variables
clr.b sysx-DB(a6)
lea dumpqueue-DB(a6),a0
move.l a0,dqreadptr-DB(a6)
move.l a0,dqwriteptr-DB(a6)
clr.w dqentries-DB(a6)
; Enable & exit
movea.l 4.w,a6
jsr -$7e(a6) ;Enable()
movem.l (sp)+,d2/a2/a6
rts
ENDC
; *************************************************************************
; *************************************************************************
; *********** P U B L I C F U N C T I O N S ***********
; *************************************************************************
; *************************************************************************
IFEQ EASY
XDEF _InitModule,_PlayModule
XDEF _InitPlayer,_RemPlayer,_StopPlayer
XDEF _ContModule
ENDC
; *************************************************************************
; InitModule(a0 = module) -- extract expansion data etc.. from V3.xx module
; *************************************************************************
_InitModule: movem.l a2-a3/d2,-(sp)
move.l a0,-(sp)
beq IM_exit ;0 => xit
IFNE RELVOL
movea.l mmd_songinfo(a0),a1 ;MMD0song
move.b msng_mastervol(a1),d0 ;d0 = mastervol
ext.w d0
lea trackdataptrs,a2
cmp.b #'2',3(a0) ;MMD2?
bne.s IM_mmd01
move.w msng_numtracks(a1),d1
subq.w #1,d1
movea.l msng_trkvoltbl(a1),a1
bra.s IM_loop0
IM_mmd01 lea msng_trkvol(a1),a1 ;a1 = trkvol
moveq #MAX_MMD1_TRACKS-1,d1
IM_loop0 move.b (a1)+,d2 ;get vol...
ext.w d2
move.l (a2)+,a3 ;pointer to track data
mulu d0,d2 ;mastervol * trackvol
lsr.w #4,d2
move.w d2,trk_trackvol(a3)
dbf d1,IM_loop0
ENDC
IFNE SYNTH
lea trackdataptrs,a2
moveq #3,d1
IM_loop1 move.l (a2)+,a3
clr.l trk_synthptr(a3)
clr.b trk_synthtype(a3)
dbf d1,IM_loop1
ENDC
lea holdvals,a2
movea.l a0,a3
move.l mmd_expdata(a0),d0 ;expdata...
IFEQ MIDI
beq.s IM_clrhlddec ;none here
ENDC
IFNE MIDI
beq.w IM_clrhlddec
ENDC
move.l d0,a1
move.l 4(a1),d0 ;exp_smp
IFEQ MIDI
beq.s IM_clrhlddec ;again.. nothing
ENDC
IFNE MIDI
beq.w IM_clrhlddec
ENDC
move.l d0,a0 ;InstrExt...
move.w 8(a1),d2 ;# of entries
IFEQ MIDI
beq.s IM_clrhlddec
ENDC
IFNE MIDI
beq.w IM_clrhlddec
ENDC
subq.w #1,d2 ;-1 (for dbf)
move.w 10(a1),d0 ;entry size
movea.l mmd_songinfo(a3),a3 ;MMD0song
IFNE MIDI
lea 4*63(a2),a1 ;pointer to ext_midipsets...
ENDC
IM_loop2 clr.b 126(a2) ;clear finetune
cmp.w #3,d0
ble.s IM_noftune
move.b 3(a0),126(a2) ;InstrExt.finetune -> finetune
IM_noftune clr.b 189(a2) ;clear flags
cmp.w #6,d0
blt.s IM_noflags
move.b 5(a0),189(a2) ;InstrExt.flags -> flags
bra.s IM_gotflags
IM_noflags cmp.w #1,inst_replen(a3)
bls.s IM_gotflags
bset #0,189(a2)
IM_gotflags
IFNE MIDI
cmp.w #2,d0
ble.s IM_nsmnoff
tst.b 2(a0) ;suppress MIDI note off?
beq.s IM_nsmnoff
bset #7,inst_midich(a3)
IM_nsmnoff move.b inst_midipreset(a3),d1
ext.w d1
move.w d1,(a1)
cmp.w #8,d0
ble.s IM_nolongpset
move.w 6(a0),(a1) ;-> ext_midipsets
btst #1,5(a0)
beq.s IM_nolongpset
bset #6,inst_midich(a3)
IM_nolongpset addq.l #2,a1
ENDC
move.b 1(a0),63(a2) ;InstrExt.decay -> decay
move.b (a0),(a2)+ ;InstrExt.hold -> holdvals
adda.w d0,a0 ;ptr to next InstrExt
addq.l #8,a3 ;next instrument...
dbf d2,IM_loop2
bra.s IM_exit
IM_clrhlddec move.w #3*63-1,d0 ;no InstrExt => clear holdvals/decays
IM_loop3 clr.w (a2)+ ;..and finetunes/flags/ext_psets
dbf d0,IM_loop3
movea.l (sp),a0
; -------- For (very old) MMDs, with no InstrExt, set flags/SSFLG_LOOP,
; -------- also copy inst_midipreset to ext_midipsets.
movea.l mmd_songinfo(a0),a3
lea flags,a2
IFNE MIDI
lea ext_midipsets,a1
ENDC
moveq #62,d0
IM_loop4 cmp.w #1,inst_replen(a3)
bls.s IM_noreptflg
bset #0,(a2)
IM_noreptflg addq.l #1,a2
IFNE MIDI
move.b inst_midipreset(a3),d1
ext.w d1
move.w d1,(a1)+
ENDC
addq.l #8,a3 ;next inst
dbf d0,IM_loop4
IM_exit addq.l #4,sp
movem.l (sp)+,a2-a3/d2
rts
; *************************************************************************
; InitPlayer() -- allocate interrupt, audio, serial port etc...
; *************************************************************************
_InitPlayer:
IFNE MIDI
bsr.w _GetSerial
tst.l d0
bne.s IP_error
ENDC
bsr.w _AudioInit
tst.l d0
bne.s IP_error
rts
IP_error bsr.s _RemPlayer
moveq #-1,d0
rts
; *************************************************************************
; RemPlayer() -- free interrupt, audio, serial port etc..
; *************************************************************************
_RemPlayer: move.b _timeropen,d0
beq.s RP_notimer ;timer is not ours
bsr.s _StopPlayer
RP_notimer: bsr.w _AudioRem
IFNE MIDI
bra.w _FreeSerial
ELSEIF
rts
ENDC
; *************************************************************************
; StopPlayer() -- stop the music
; *************************************************************************
_StopPlayer: lea DB,a1
move.b _timeropen-DB(a1),d0
beq.s SP_end ;res. alloc fail.
IFNE CIAB
movea.l craddr-DB(a1),a0
bclr #0,(a0) ;stop timer
ENDC
move.l _module-DB(a1),d0
beq.s SP_nomod
move.l d0,a0
clr.w mmd_pstate(a0)
clr.l _module-DB(a1)
SP_nomod
IFNE MIDI
clr.b lastcmdbyte-DB(a1)
ENDC
bra.w SoundOff
SP_end rts
_ContModule tst.b _timeropen
beq.s SP_end
movea.l craddr,a1
bclr #0,(a1)
move.l a0,-(sp)
bsr.w SoundOff
move.l (sp)+,a0
moveq #0,d0
bra.s contpoint
; *************************************************************************
; PlayModule(a0 = module) -- initialize & play it!
; *************************************************************************
_PlayModule: st d0
contpoint movem.l a0/d0,-(sp)
bsr _InitModule
movem.l (sp)+,a0/d0
move.l a6,-(sp)
lea DB,a6
tst.b _timeropen-DB(a6)
beq PM_end ;resource allocation failure
move.l a0,d1
beq PM_end ;module failure
IFNE CIAB
movea.l craddr-DB(a6),a1
bclr #0,(a1) ;stop timer...
ENDC
clr.l _module-DB(a6)
IFNE MIDI
clr.b lastcmdbyte-DB(a6)
ENDC
move.w _modnum,d1
beq.s PM_modfound
PM_nextmod tst.l mmd_expdata(a0)
beq.s PM_modfound
move.l mmd_expdata(a0),a1
tst.l (a1)
beq.s PM_modfound ;no more modules here!
move.l (a1),a0
subq.w #1,d1
bgt.s PM_nextmod
PM_modfound cmp.b #'T',3(a0)
bne.s PM_nomodT
move.b #'0',3(a0) ;change MCNT to MCN0
PM_nomodT movea.l mmd_songinfo(a0),a1 ;song
move.b msng_tempo2(a1),mmd_counter(a0) ;init counter
btst #0,msng_flags(a1)
bne.s PM_filon
bset #1,$bfe001
bra.s PM_filset
PM_filon bclr #1,$bfe001
PM_filset tst.b d0
beq.s PM_noclr
clr.l mmd_pline(a0)
clr.l rptline-DB(a6)
clr.w blkdelay-DB(a6)
; ---------- Set 'pblock' and 'pseq' to correct values...
PM_noclr cmp.b #'2',3(a0)
bne.s PM_oldpbset
move.w mmd_psecnum(a0),d1
move.l a2,-(sp) ;need extra register
movea.l msng_sections(a1),a2
add.w d1,d1
move.w 0(a2,d1.w),d1 ;get sequence number
add.w d1,d1
add.w d1,d1
move.w d1,mmd_pseq(a0)
movea.l msng_pseqs(a1),a2
movea.l 0(a2,d1.w),a2 ;PlaySeq...
move.w mmd_pseqnum(a0),d1
add.w d1,d1
move.w 42(a2,d1.w),d1 ;and the correct block..
move.l (sp)+,a2
bra.s PM_setblk
PM_oldpbset move.w mmd_pseqnum(a0),d1
add.w #msng_playseq,d1
move.b 0(a1,d1.w),d1 ;get first playseq entry
ext.w d1
PM_setblk move.w d1,mmd_pblock(a0)
move.w #-1,mmd_pstate(a0)
move.l a0,_module-DB(a6)
btst #5,msng_flags2(a1) ;BPM?
seq bpmcounter-DB(a6)
IFNE CIAB
move.w msng_deftempo(a1),d0 ;get default tempo
movea.l craddr-DB(a6),a1
bsr.w _SetTempo ;set default tempo
bset #0,(a1) ;start timer => PLAY!!
ENDC
PM_end move.l (sp)+,a6
rts
; *************************************************************************
_AudioInit: movem.l a4/a6/d2-d3,-(sp)
lea DB,a4
moveq #0,d2
movea.l 4.w,a6
; +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ alloc signal bit
IFNE AUDDEV
moveq #1,d2
moveq #-1,d0
jsr -$14a(a6) ;AllocSignal()
tst.b d0
bmi.w initerr
move.b d0,sigbitnum-DB(a4)
; +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ prepare IORequest
lea allocport-DB(a4),a1
move.b d0,15(a1) ;set mp_SigBit
move.l a1,-(sp)
suba.l a1,a1
jsr -$126(a6) ;FindTask(0)
move.l (sp)+,a1
move.l d0,16(a1) ;set mp_SigTask
lea reqlist-DB(a4),a0
move.l a0,(a0) ;NEWLIST begins...
addq.l #4,(a0)
clr.l 4(a0)
move.l a0,8(a0) ;NEWLIST ends...
; +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ open audio.device
moveq #2,d2
lea allocreq-DB(a4),a1
lea audiodevname-DB(a4),a0
moveq #0,d0
moveq #0,d1
movea.l 4.w,a6
jsr -$1bc(a6) ;OpenDevice()
tst.b d0
bne.w initerr
st audiodevopen-DB(a4)
; +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ open cia resource
moveq #3,d2
ENDC
IFNE CIAB
cmp.b #50,$212(a6) ;ExecBase->VBlankFrequency
beq.s init_pal
move.l #474326,timerdiv-DB(a4) ;Assume that CIA freq is 715 909 Hz
move.l #3579545/2,bpmdiv-DB(a4)
init_pal moveq #0,d3
lea cianame-DB(a4),a1
move.b #'a',3(a1)
open_ciares moveq #0,d0
jsr -$1f2(a6) ;OpenResource()
move.l d0,_ciaresource
beq.s try_CIAB
moveq #4,d2
move.l d0,a6
lea timerinterrupt-DB(a4),a1
moveq #0,d0 ;Timer A
jsr -$6(a6) ;AddICRVector()
tst.l d0
beq.s got_timer
addq.l #4,d3 ;add base addr index
lea timerinterrupt-DB(a4),a1
moveq #1,d0 ;Timer B
jsr -$6(a6) ;AddICRVector()
tst.l d0
beq.s got_timer
try_CIAB lea cianame-DB(a4),a1
cmp.b #'a',3(a1)
bne.s initerr
addq.b #1,3(a1)
moveq #8,d3 ;CIAB base addr index = 8
bra.w open_ciares
; +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ attach interrupt
got_timer lea craddr+8-DB(a4),a6
move.l cia_addr(pc,d3.w),d0
move.l d0,(a6)
sub.w #$100,d0
move.l d0,-(a6)
moveq #2,d3 ;assume timer B
btst #9,d0 ;timer A or B ?
bne.s got_timerB
subq.b #1,d3 ;not timer B -> subtract 1
add.w #$100,d0 ;calc offset to timer control reg
got_timerB add.w #$900,d0
move.l d0,-(a6)
move.l d0,a0 ;get Control Register
and.b #%10000000,(a0) ;clear CtrlReg bits 0 - 6
move.b d3,_timeropen-DB(a4) ;d3: 1 = TimerA 2 = TimerB
ENDC
IFNE VBLANK
moveq #5,d0 ;INTB_VERTB
lea timerinterrupt-DB(a4),a1
jsr -$a8(a6) ;AddIntServer
st _timeropen-DB(a4)
ENDC
moveq #0,d0
initret: movem.l (sp)+,a4/a6/d2-d3
rts
initerr: move.l d2,d0
bra.s initret
cia_addr: dc.l $BFE501,$BFE701,$BFD500,$BFD700
_AudioRem: movem.l a5-a6,-(sp)
lea DB,a5
moveq #0,d0
move.b _timeropen,d0
beq.s rem1
; +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ remove interrupt
clr.b _timeropen
IFNE CIAB
move.l _ciaresource,a6
lea timerinterrupt-DB(a5),a1
subq.b #1,d0
jsr -$c(a6) ;RemICRVector
ENDC
IFNE VBLANK
movea.l 4.w,a6
lea timerinterrupt(pc),a1
moveq #5,d0
jsr -$ae(a6) ;RemIntServer
ENDC
rem1:
IFNE AUDDEV
movea.l 4.w,a6
tst.b audiodevopen-DB(a5)
beq.s rem2
move.w #$000f,$dff096 ;stop audio DMA
; +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ close audio.device
lea allocreq-DB(a5),a1
jsr -$1c2(a6) ;CloseDevice()
clr.b audiodevopen-DB(a5)
rem2: moveq #0,d0
move.b sigbitnum-DB(a5),d0
bmi.s rem3
; +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ free signal bit
jsr -$150(a6) ;FreeSignal()
st sigbitnum-DB(a5)
rem3:
ENDC
movem.l (sp)+,a5-a6
rts
IFNE MIDI
_GetSerial: movem.l a5-a6,-(sp) ;Get serial port for MIDI
lea DB,a5
bsr.s GetSer2
tst.l d0 ;got the port??
beq.s rgser ;yes
movea.l 4.w,a6 ;no..try to flush serial.device:
jsr -$84(a6) ;Forbid
lea $15e(a6),a0 ;ExecBase->DeviceList
lea serdev-DB(a5),a1 ;"serial.device"
jsr -$114(a6) ;FindName
tst.l d0
beq.s serdnotf ;no serial.device!!
move.l d0,a1
jsr -$1b6(a6) ;RemDevice
serdnotf: jsr -$8a(a6) ;and Permit
bsr.s GetSer2 ;now try it again...
rgser: movem.l (sp)+,a5-a6
rts
GetSer2: movea.l 4.w,a6
moveq #0,d0
lea miscresname-DB(a5),a1
jsr -$1f2(a6) ;OpenResource()
move.l d0,miscresbase-DB(a5)
tst.l d0
beq.s gserror
move.l d0,a6
lea medname-DB(a5),a1
moveq #0,d0 ;serial port
jsr -$6(a6) ;AllocMiscResource()
tst.l d0
bne.s gserror
lea medname-DB(a5),a1
moveq #1,d0 ;serial bits
jsr -$6(a6)
tst.l d0
beq.s gs2_allocok
moveq #0,d0
jsr -$c(a6) ;bits failed -> Free serial port
bra.s gserror
gs2_allocok move.w $dff01c,d0
btst #0,d0
sne intrson-DB(a5)
moveq #0,d0 ;TBE
lea serinterrupt-DB(a5),a1
move.l 4.w,a6
jsr -$a2(a6) ;SetIntVector()
move.l d0,prevtbe-DB(a5)
move.w #$8001,$dff09a ;TBE on
move.w #114,$dff032 ;set baud rate (SERPER)
st serportalloc-DB(a5)
moveq #0,d0
rts
gserror: moveq #-1,d0
rts
_FreeSerial: movem.l a5-a6,-(sp)
lea DB,a5
tst.l miscresbase-DB(a5)
beq.s retfs
tst.b serportalloc-DB(a5)
beq.s retfs
wmb_loop move.w $dff018,d0 ;WAIT until all data sent
btst #12,d0 ;test TSRE bit of SERDAT
beq.s wmb_loop
move.w #$0001,$dff09a ;disable TBE
movea.l 4.w,a6
move.l prevtbe-DB(a5),a1
moveq #0,d0
jsr -$a2(a6) ;SetIntVector()
fs_noptbe movea.l miscresbase-DB(a5),a6
moveq #0,d0 ;serial port
jsr -$c(a6) ;FreeMiscResource()
moveq #1,d0 ;serial bits
jsr -$c(a6)
clr.b serportalloc-DB(a5)
clr.b lastcmdbyte-DB(a5)
retfs: movem.l (sp)+,a5-a6
rts
; Message number in d0.
_InitMIDIDump: tst.b serportalloc
beq.s idd_rts
movem.l a5/a6,-(sp) ;a1 = data pointer, d1 = length
lea DB,a5
movea.l 4.w,a6 ;ExecBase
jsr -$78(a6) ;Disable()
cmp.w #16,dqentries-DB(a5) ;dump queue full?
bge.s idd_exit ;exit without doing anything
lea dqwriteptr-DB(a5),a1
movea.l (a1),a0
move.w d0,(a0)+ ;store message number
cmpa.l a1,a0 ;queue end?
bne.s idd_noresetbuff
lea dumpqueue-DB(a5),a0 ;reset write pointer
idd_noresetbuff move.l a0,(a1) ;and write it back.
addq.w #1,dqentries-DB(a5)
tst.b sysx-DB(a5) ;already sending data?
bne.s idd_exit ;yes. Don't initiate new send.
clr.b lastcmdbyte-DB(a5)
bsr StartNewDump
move.w $dff018,d0 ;SERDATR
btst #13,d0
beq.s idd_exit
move.w #$8001,$dff09c ;request TBE
idd_exit jsr -$7e(a6) ;Enable()
movem.l (sp)+,a5/a6
idd_rts rts
SerIntHandler: move.w #$4000,$9a(a0) ;disable..(Interrupts are enabled anyway)
move.w #1,$9c(a0) ;clear intreq bit
tst.b sysx-buffptr(a1) ;sysx??
bne.s sih_sysx
move.w bytesinbuff-buffptr(a1),d0 ;bytesinbuff
beq.s exsih ;buffer empty
movea.l readbuffptr-buffptr(a1),a5 ;get buffer read pointer
move.w #$100,d1 ;Stop bit
move.b (a5)+,d1 ;get byte
move.w d1,$30(a0) ;and push it to SERDAT
cmpa.l a1,a5 ;shall we reset ptr?
bne.s norrbuffptr ;not yet..
lea -256(a1),a5
norrbuffptr subq.w #1,d0 ;one less bytes in buffer
move.w d0,bytesinbuff-buffptr(a1) ;remember it
move.l a5,readbuffptr-buffptr(a1) ;push new read ptr back
exsih move.w #$c000,$9a(a0)
rts
sih_sysx move.w #$100,d1
movea.l sysxptr-buffptr(a1),a5 ;data pointer
move.b (a5)+,d1
move.l a5,sysxptr-buffptr(a1)
move.w d1,$30(a0) ;-> SERDAT
subq.l #1,sysxleft-buffptr(a1) ;sub data left length
bne.s exsih ;not 0w
lea DB,a5
clr.b lastcmdbyte-DB(a5)
bsr.s StartNewDump
bra.s exsih
StartNewDump: tst.w dqentries-DB(a5) ;queue empty?
beq.s snd_exit2
movea.l dqreadptr-DB(a5),a1 ;get read pointer
move.w (a1)+,d0 ;get message number (D0)
cmpa.l #dqwriteptr,a1 ;queue end?
bne.s snd_noresetbuff
lea dumpqueue-DB(a5),a1 ;reset write pointer
snd_noresetbuff move.l a1,dqreadptr-DB(a5) ;and write it back.
subq.w #1,dqentries-DB(a5)
; then attempt to search the given message (# in D0)
move.l _module-DB(a5),d1
beq.s StartNewDump
move.l d1,a1
move.l mmd_expdata(a1),d1
beq.s StartNewDump
move.l d1,a1
move.l 52(a1),d1 ;exp_dump
beq.s StartNewDump
move.l d1,a1
cmp.w (a1),d0
bge.s StartNewDump
addq.l #8,a1 ;points to MMDDump ptr table
add.w d0,d0
add.w d0,d0 ;number *= 4
adda.w d0,a1
movea.l (a1),a1
; initialize send variables (msg addr. in A0)
snd_found move.l (a1)+,sysxleft-DB(a5) ;length
move.l (a1),sysxptr-DB(a5) ;data pointer
st sysx-DB(a5)
rts
snd_exit2 clr.b sysx-DB(a5) ;finish dump
rts
_AddMIDIData move.l a6,-(sp)
lea DB,a6
bsr.s _AddMIDId
move.l (sp)+,a6
rts
_AddMIDId movem.l a2-a3/a5,-(sp)
tst.b serportalloc-DB(a6)
beq.s retamd1
movea.l 4.w,a5
lea $dff09a,a3
move.w #$4000,(a3) ;Disable interrupts
addq.b #1,$126(a5) ;ExecBase->IDNestCnt
lea buffptr-DB(a6),a2 ;end of buffer (ptr)
move.w -130(a3),d1 ;-130(a3) = $dff018 (SERDATR)
btst #13,d1
beq.s noTBEreq
move.w #$8001,2(a3) ;request TBE [2(a3) = $dff09c]
noTBEreq movea.l (a2),a1 ;buffer pointer
subq.w #1,d0 ;-1 for DBF
adddataloop move.b (a0)+,d1 ;get byte
bpl.s norscheck ;this isn't a status byte
cmp.b #$ef,d1 ;ignore system messages
bhi.s norscheck
cmp.b lastcmdbyte-DB(a6),d1 ;same as previous status byte?
beq.s samesb ;yes, skip
move.b d1,lastcmdbyte-DB(a6) ;no, don't skip but store.
norscheck move.b d1,(a1)+ ;push to midi send buffer
addq.w #1,8(a2)
samesb cmpa.l a2,a1 ;end of buffer??
bne.s noresbuffptr ;no.
lea sendbuffer-DB(a6),a1 ;reset
noresbuffptr dbf d0,adddataloop
move.l a1,(a2) ;push back new buffer ptr
subq.b #1,$126(a5)
bge.s retamd1
move.w #$c000,(a3) ;enable interrupts again
retamd1 movem.l (sp)+,a2-a3/a5
rts
ENDC
DATA
DB: ;Data base pointer
IFNE MIDI
sendbuffer ds.b 256
buffptr dc.l sendbuffer
readbuffptr dc.l sendbuffer
bytesinbuff dc.w 0
sysx dc.b 0
lastcmdbyte dc.b 0
sysxptr dc.l 0
sysxleft dc.l 0
dumpqueue ds.w 16
dqwriteptr dc.l dumpqueue
dqreadptr dc.l dumpqueue
dqentries dc.w 0
ENDC
miscresbase dc.l 0
timerdiv dc.l 470000
IFNE AUDDEV
audiodevopen dc.b 0
sigbitnum dc.b -1
ENDC
IFNE MIDI
serportalloc dc.b 0
ENDC
even
IFNE MIDI
preschgdata dc.l 0
noteondata dc.l 0
ENDC
_module dc.l 0
dmaonmsk dc.w 0 ;\_May not be
IFNE MIDI
bytesinnotebuff dc.w 0 ;/ separated!
noteonbuff ds.b (MAX_NUMTRACKS+2)*3
even
intrson dc.b 0,0
prevtbe dc.l 0
ENDC
IFNE CIAB
_ciaresource dc.l 0
craddr dc.l 0
dc.l 0 ;tloaddr
dc.l 0 ;thiaddr
ENDC
timerinterrupt dc.w 0,0,0,0,0
dc.l timerintname,DB
dc.l _IntHandler
IFNE MIDI
serinterrupt dc.w 0,0,0,0,0
dc.l serintname,buffptr,SerIntHandler
ENDC
IFNE AUDDEV
allocport dc.l 0,0 ;succ, pred
dc.b 4,0 ;NT_MSGPORT
dc.l 0 ;name
dc.b 0,0 ;flags = PA_SIGNAL
dc.l 0 ;task
reqlist dc.l 0,0,0 ;list head, tail and tailpred
dc.b 5,0
allocreq dc.l 0,0
dc.b 0,127 ;NT_UNKNOWN, use maximum priority (127)
dc.l 0,allocport ;name, replyport
dc.w 68 ;length
dc.l 0 ;io_Device
dc.l 0 ;io_Unit
dc.w 0 ;io_Command
dc.b 0,0 ;io_Flags, io_Error
dc.w 0 ;ioa_AllocKey
dc.l sttempo ;ioa_Data
dc.l 1 ;ioa_Length
dc.w 0,0,0 ;ioa_Period, Volume, Cycles
dc.w 0,0,0,0,0,0,0,0,0,0 ;ioa_WriteMsg
audiodevname dc.b 'audio.device',0
ENDC
IFNE CIAB
cianame dc.b 'ciax.resource',0
_timeropen dc.b 0
ENDC
timerintname dc.b 'OMEDTimerInterrupt',0
IFNE MIDI
serintname dc.b 'OMEDSerialInterrupt',0
miscresname dc.b 'misc.resource',0
serdev dc.b 'serial.device',0
medname dc.b 'OctaMED Pro modplayer',0
ENDC
even
IFNE MIDI
midiresd dc.b $e0,$00,$40,$b0,$01,$00
midicontrnum ds.b 16
prevmidicpres dc.l 0,0,0,0,0,0,0,0 ; 16 * 2 bytes
prevmidipbend dc.w $2000,$2000,$2000,$2000,$2000,$2000,$2000,$2000
dc.w $2000,$2000,$2000,$2000,$2000,$2000,$2000,$2000
ENDC
; TRACK-data structures (see definitions at the end of this file)
t03d ds.b 22
dc.l $dff0a0
ds.b 71
dc.b $ff
ds.b 22
dc.l $dff0b0
ds.b 71
dc.b $ff
ds.b 22
dc.l $dff0c0
ds.b 71
dc.b $ff
ds.b 22
dc.l $dff0d0
ds.b 71
dc.b $ff
t463d ds.b (MAX_NUMTRACKS-4)*T415SZ
trackdataptrs dc.l t03d,t03d+T03SZ,t03d+2*T03SZ,t03d+3*T03SZ
; Build pointer table. This works on Devpac assembler, other assemblers
; may need modifications.
TRKCOUNT SET 0
REPT (MAX_NUMTRACKS-4)
dc.l t463d+TRKCOUNT
TRKCOUNT SET TRKCOUNT+T415SZ
ENDR
nextblock dc.b 0 ;\ DON'T SEPARATE
nxtnoclrln dc.b 0 :/
numtracks dc.w 0 ;\ DON'T SEPARATE
numlines dc.w 0 ;/
nextblockline dc.w 0
rptline dc.w 0 ;\ DON'T SEPARATE
rptcounter dc.w 0 ;/
blkdelay dc.w 0 ;block delay (PT PatternDelay)
bpmcounter dc.w 0
bpmdiv dc.l 3546895/2
; Fields in struct InstrExt (easier to access this way rather than
; searching through the module).
holdvals ds.b 63
decays ds.b 63
finetunes ds.b 63
flags ds.b 63
ext_midipsets ds.w 63
; Below are the period tables. There's one table for each finetune position.
IFNE SYNTH|IFFMOCT
dc.w 3424,3232,3048,2880,2712,2560,2416,2280,2152,2032,1920,1812
dc.w 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,906
ENDC
per0 dc.w 856,808,762,720,678,640,604,570,538,508,480,453
dc.w 428,404,381,360,339,320,302,285,269,254,240,226
dc.w 214,202,190,180,170,160,151,143,135,127,120,113
dc.w 214,202,190,180,170,160,151,143,135,127,120,113
dc.w 214,202,190,180,170,160,151,143,135,127,120,113
dc.w 214,202,190,180,170,160,151,143,135,127,120,113
IFNE SYNTH|IFFMOCT
dc.w 3400,3209,3029,2859,2699,2547,2404,2269,2142,2022,1908,1801
dc.w 1700,1605,1515,1430,1349,1274,1202,1135,1071,1011,954,901
ENDC
per1 dc.w 850,802,757,715,674,637,601,567,535,505,477,450
dc.w 425,401,379,357,337,318,300,284,268,253,239,225
dc.w 213,201,189,179,169,159,150,142,134,126,119,113
dc.w 213,201,189,179,169,159,150,142,134,126,119,113
dc.w 213,201,189,179,169,159,150,142,134,126,119,113
dc.w 213,201,189,179,169,159,150,142,134,126,119,113
IFNE SYNTH|IFFMOCT
dc.w 3376,3187,3008,2839,2680,2529,2387,2253,2127,2007,1895,1788
dc.w 1688,1593,1504,1419,1340,1265,1194,1127,1063,1004,947,894
ENDC
per2 dc.w 844,796,752,709,670,632,597,563,532,502,474,447
dc.w 422,398,376,355,335,316,298,282,266,251,237,224
dc.w 211,199,188,177,167,158,149,141,133,125,118,112
dc.w 211,199,188,177,167,158,149,141,133,125,118,112
dc.w 211,199,188,177,167,158,149,141,133,125,118,112
dc.w 211,199,188,177,167,158,149,141,133,125,118,112
IFNE SYNTH|IFFMOCT
dc.w 3352,3164,2986,2819,2660,2511,2370,2237,2112,1993,1881,1776
dc.w 1676,1582,1493,1409,1330,1256,1185,1119,1056,997,941,888
ENDC
per3 dc.w 838,791,746,704,665,628,592,559,528,498,470,444
dc.w 419,395,373,352,332,314,296,280,264,249,235,222
dc.w 209,198,187,176,166,157,148,140,132,125,118,111
dc.w 209,198,187,176,166,157,148,140,132,125,118,111
dc.w 209,198,187,176,166,157,148,140,132,125,118,111
dc.w 209,198,187,176,166,157,148,140,132,125,118,111
IFNE SYNTH|IFFMOCT
dc.w 3328,3141,2965,2799,2641,2493,2353,2221,2097,1979,1868,1763
dc.w 1664,1571,1482,1399,1321,1247,1177,1111,1048,989,934,881
ENDC
per4 dc.w 832,785,741,699,660,623,588,555,524,495,467,441
dc.w 416,392,370,350,330,312,294,278,262,247,233,220
dc.w 208,196,185,175,165,156,147,139,131,124,117,110
dc.w 208,196,185,175,165,156,147,139,131,124,117,110
dc.w 208,196,185,175,165,156,147,139,131,124,117,110
dc.w 208,196,185,175,165,156,147,139,131,124,117,110
IFNE SYNTH|IFFMOCT
dc.w 3304,3119,2944,2778,2622,2475,2336,2205,2081,1965,1854,1750
dc.w 1652,1559,1472,1389,1311,1238,1168,1103,1041,982,927,875
ENDC
per5 dc.w 826,779,736,694,655,619,584,551,520,491,463,437
dc.w 413,390,368,347,328,309,292,276,260,245,232,219
dc.w 206,195,184,174,164,155,146,138,130,123,116,109
dc.w 206,195,184,174,164,155,146,138,130,123,116,109
dc.w 206,195,184,174,164,155,146,138,130,123,116,109
dc.w 206,195,184,174,164,155,146,138,130,123,116,109
IFNE SYNTH|IFFMOCT
dc.w 3280,3096,2922,2758,2603,2457,2319,2189,2066,1950,1841,1738
dc.w 1640,1548,1461,1379,1302,1229,1160,1095,1033,975,920,869
ENDC
per6 dc.w 820,774,730,689,651,614,580,547,516,487,460,434
dc.w 410,387,365,345,325,307,290,274,258,244,230,217
dc.w 205,193,183,172,163,154,145,137,129,122,115,109
dc.w 205,193,183,172,163,154,145,137,129,122,115,109
dc.w 205,193,183,172,163,154,145,137,129,122,115,109
dc.w 205,193,183,172,163,154,145,137,129,122,115,109
IFNE SYNTH|IFFMOCT
dc.w 3256,3073,2901,2738,2584,2439,2302,2173,2051,1936,1827,1725
dc.w 1628,1537,1450,1369,1292,1220,1151,1087,1026,968,914,862
ENDC
per7 dc.w 814,768,725,684,646,610,575,543,513,484,457,431
dc.w 407,384,363,342,323,305,288,272,256,242,228,216
dc.w 204,192,181,171,161,152,144,136,128,121,114,108
dc.w 204,192,181,171,161,152,144,136,128,121,114,108
dc.w 204,192,181,171,161,152,144,136,128,121,114,108
dc.w 204,192,181,171,161,152,144,136,128,121,114,108
IFNE SYNTH|IFFMOCT
dc.w 3628,3424,3232,3051,2880,2718,2565,2421,2285,2157,2036,1922
dc.w 1814,1712,1616,1525,1440,1359,1283,1211,1143,1079,1018,961
ENDC
per_8 dc.w 907,856,808,762,720,678,640,604,570,538,508,480
dc.w 453,428,404,381,360,339,320,302,285,269,254,240
dc.w 226,214,202,190,180,170,160,151,143,135,127,120
dc.w 226,214,202,190,180,170,160,151,143,135,127,120
dc.w 226,214,202,190,180,170,160,151,143,135,127,120
dc.w 226,214,202,190,180,170,160,151,143,135,127,120
IFNE SYNTH|IFFMOCT
dc.w 3588,3387,3197,3017,2848,2688,2537,2395,2260,2133,2014,1901
dc.w 1794,1693,1598,1509,1424,1344,1269,1197,1130,1067,1007,950
ENDC
per_7 dc.w 900,850,802,757,715,675,636,601,567,535,505,477
dc.w 450,425,401,379,357,337,318,300,284,268,253,238
dc.w 225,212,200,189,179,169,159,150,142,134,126,119
dc.w 225,212,200,189,179,169,159,150,142,134,126,119
dc.w 225,212,200,189,179,169,159,150,142,134,126,119
dc.w 225,212,200,189,179,169,159,150,142,134,126,119
IFNE SYNTH|IFFMOCT
dc.w 3576,3375,3186,3007,2838,2679,2529,2387,2253,2126,2007,1894
dc.w 1788,1688,1593,1504,1419,1339,1264,1193,1126,1063,1003,947
ENDC
per_6 dc.w 894,844,796,752,709,670,632,597,563,532,502,474
dc.w 447,422,398,376,355,335,316,298,282,266,251,237
dc.w 223,211,199,188,177,167,158,149,141,133,125,118
dc.w 223,211,199,188,177,167,158,149,141,133,125,118
dc.w 223,211,199,188,177,167,158,149,141,133,125,118
dc.w 223,211,199,188,177,167,158,149,141,133,125,118
IFNE SYNTH|IFFMOCT
dc.w 3548,3349,3161,2984,2816,2658,2509,2368,2235,2110,1991,1879
dc.w 1774,1674,1580,1492,1408,1329,1254,1184,1118,1055,996,940
ENDC
per_5 dc.w 887,838,791,746,704,665,628,592,559,528,498,470
dc.w 444,419,395,373,352,332,314,296,280,264,249,235
dc.w 222,209,198,187,176,166,157,148,140,132,125,118
dc.w 222,209,198,187,176,166,157,148,140,132,125,118
dc.w 222,209,198,187,176,166,157,148,140,132,125,118
dc.w 222,209,198,187,176,166,157,148,140,132,125,118
IFNE SYNTH|IFFMOCT
dc.w 3524,3326,3140,2963,2797,2640,2492,2352,2220,2095,1978,1867
dc.w 1762,1663,1570,1482,1399,1320,1246,1176,1110,1048,989,933
ENDC
per_4 dc.w 881,832,785,741,699,660,623,588,555,524,494,467
dc.w 441,416,392,370,350,330,312,294,278,262,247,233
dc.w 220,208,196,185,175,165,156,147,139,131,123,117
dc.w 220,208,196,185,175,165,156,147,139,131,123,117
dc.w 220,208,196,185,175,165,156,147,139,131,123,117
dc.w 220,208,196,185,175,165,156,147,139,131,123,117
IFNE SYNTH|IFFMOCT
dc.w 3500,3304,3118,2943,2778,2622,2475,2336,2205,2081,1964,1854
dc.w 1750,1652,1559,1472,1389,1311,1237,1168,1102,1041,982,927
ENDC
per_3 dc.w 875,826,779,736,694,655,619,584,551,520,491,463
dc.w 437,413,390,368,347,328,309,292,276,260,245,232
dc.w 219,206,195,184,174,164,155,146,138,130,123,116
dc.w 219,206,195,184,174,164,155,146,138,130,123,116
dc.w 219,206,195,184,174,164,155,146,138,130,123,116
dc.w 219,206,195,184,174,164,155,146,138,130,123,116
IFNE SYNTH|IFFMOCT
dc.w 3472,3277,3093,2920,2756,2601,2455,2317,2187,2064,1949,1839
dc.w 1736,1639,1547,1460,1378,1301,1228,1159,1094,1032,974,920
ENDC
per_2 dc.w 868,820,774,730,689,651,614,580,547,516,487,460
dc.w 434,410,387,365,345,325,307,290,274,258,244,230
dc.w 217,205,193,183,172,163,154,145,137,129,122,115
dc.w 217,205,193,183,172,163,154,145,137,129,122,115
dc.w 217,205,193,183,172,163,154,145,137,129,122,115
dc.w 217,205,193,183,172,163,154,145,137,129,122,115
IFNE SYNTH|IFFMOCT
dc.w 3448,3254,3072,2899,2737,2583,2438,2301,2172,2050,1935,1827
dc.w 1724,1627,1536,1450,1368,1292,1219,1151,1086,1025,968,913
ENDC
per_1 dc.w 862,814,768,725,684,646,610,575,543,513,484,457
dc.w 431,407,384,363,342,323,305,288,272,256,242,228
dc.w 216,203,192,181,171,161,152,144,136,128,121,114
dc.w 216,203,192,181,171,161,152,144,136,128,121,114
dc.w 216,203,192,181,171,161,152,144,136,128,121,114
dc.w 216,203,192,181,171,161,152,144,136,128,121,114
_periodtable
dc.l per_8,per_7,per_6,per_5,per_4,per_3,per_2,per_1,per0
dc.l per1,per2,per3,per4,per5,per6,per7
IFND __G2
section "datachip",data,chip ;for A68k
ENDC
IFD __G2
section "datachip",data_c ;this is for Devpac 2
ENDC
XDEF _modnum
IFNE EASY
easymod INCBIN "module" ;<<<<< MODULE NAME HERE!
ENDC
_chipzero dc.l 0
_modnum dc.w 0 ;number of module to play
; SPECIAL... FREE CHANNEL 0
XDEF _freech0
_freech0 dc.w 0
; the track-data structure definition:
trk_prevnote EQU 0 ;previous note number
trk_previnstr EQU 1 ;previous instrument number
trk_prevvol EQU 2 ;previous volume
trk_prevmidich EQU 3 ;previous MIDI channel
trk_cmd EQU 4 ;command (the 3rd number from right)
trk_cmdqual EQU 5 ;command qualifier (infobyte, databyte..)
trk_prevmidin EQU 6 ;previous MIDI note
trk_noteoffcnt EQU 7 ;note-off counter (hold)
trk_inithold EQU 8 ;default hold for this instrument
trk_initdecay EQU 9 ;default decay for....
trk_stransp EQU 10 ;instrument transpose
trk_finetune EQU 11 ;finetune
trk_soffset EQU 12 ;new sample offset
trk_previnstra EQU 14 ;address of the previous instrument data
trk_trackvol EQU 18
; the following data only on tracks 0 - 3
trk_prevper EQU 20 ;previous period
trk_audioaddr EQU 22 ;hardware audio channel base address
trk_sampleptr EQU 26 ;pointer to sample
trk_samplelen EQU 30 ;length (>> 1)
trk_porttrgper EQU 32 ;portamento (cmd 3) target period
trk_vibshift EQU 34 ;vibrato shift for ASR instruction
trk_vibrspd EQU 35 ;vibrato speed/size (cmd 4 qualifier)
trk_vibrsz EQU 36 ;vibrato size
trk_synthptr EQU 38 ;pointer to synthetic/hybrid instrument
trk_arpgoffs EQU 42 ;SYNTH: current arpeggio offset
trk_arpsoffs EQU 44 ;SYNTH: arpeggio restart offset
trk_volxcnt EQU 46 ;SYNTH: volume execute counter
trk_wfxcnt EQU 47 ;SYNTH: waveform execute counter
trk_volcmd EQU 48 ;SYNTH: volume command pointer
trk_wfcmd EQU 50 ;SYNTH: waveform command pointer
trk_volwait EQU 52 ;SYNTH: counter for WAI (volume list)
trk_wfwait EQU 53 ;SYNTH: counter for WAI (waveform list)
trk_synthvibspd EQU 54 ;SYNTH: vibrato speed
trk_wfchgspd EQU 56 ;SYNTH: period change
trk_perchg EQU 58 ;SYNTH: curr. period change from trk_prevper
trk_envptr EQU 60 ;SYNTH: envelope waveform pointer
trk_synvibdep EQU 64 ;SYNTH: vibrato depth
trk_synvibwf EQU 66 ;SYNTH: vibrato waveform
trk_synviboffs EQU 70 ;SYNTH: vibrato pointer
trk_initvolxspd EQU 72 ;SYNTH: volume execute speed
trk_initwfxspd EQU 73 ;SYNTH: waveform execute speed
trk_volchgspd EQU 74 ;SYNTH: volume change
trk_prevnote2 EQU 75 ;SYNTH: previous note
trk_synvol EQU 76 ;SYNTH: current volume
trk_synthtype EQU 77 ;>0 = synth, -1 = hybrid, 0 = no synth
trk_periodtbl EQU 78 ;pointer to period table
trk_prevportspd EQU 82 ;portamento (cmd 3) speed
trk_decay EQU 84 ;decay
trk_fadespd EQU 85 ;decay speed
trk_envrestart EQU 86 ;SYNTH: envelope waveform restart point
trk_envcount EQU 90 ;SYNTH: envelope counter
trk_split EQU 91 ;0 = this channel not splitted (OctaMED V2)
trk_vibroffs EQU 92 ;vibrato table offset \ DON'T SEPARATE
trk_tremoffs EQU 93 ;tremolo table offset /
trk_tremsz EQU 94 ;tremolo size
trk_tremspd EQU 96 ;tremolo speed
trk_tempvol EQU 97 ;temporary volume (for tremolo)
END